QT实现一个图片透视变换的小玩意

版权声明:本文为博主原创文章,未经博主允许不得转载,转载请设置文章链接! https://blog.csdn.net/qq_30460905/article/details/88383410

近来有点烦,不想看论文,不想做项目,无聊之余把好久之前想到的用qt做一个图片透视变换的小工具的想法实现了一下。。。详细如下:

说明:对于有些平时拍的图片可能产生了透视效果,而你想得到正向拍摄的效果,你就可以根据opencv中的透视变换,选择矩形物体图片中的四个点,变换到正常图像状态,还有其他用处,自己去想吧,哈哈。

0. 首先看一下效果,有兴趣可以继续往下看,

1. 使用说明

(1)首先打开一张图片,调整需要透视变换物体在左边图形框中完全显示。

(2)点击左下角 ‘选择角点’ 按钮,然后按照顺时针顺序依次点击四个角点,点击“选择结束”,不点也没关系。

(3)输入转换后的图片高度和宽度,默认值为200,320,点击“透视变换“ 按钮即可显示变换后的图像。

(4)点击”保存图片“ 按钮,选择保存位置,输入文件名,不要忘了加后缀 ”.jpg“ 。

2.创建一个qt桌面项目,添加opencv库,pro文件如下

#-------------------------------------------------
#
# Project created by QtCreator 2019-03-04T09:22:39
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = perspective_img
TEMPLATE = app
#include opencv files
INCLUDEPATH += /usr/include \
                /usr/include/opencv \
                /usr/include/opencv2

LIBS += /usr/lib/x86_64-linux-gnu/libopencv_highgui.so \
        /usr/lib/x86_64-linux-gnu/libopencv_core.so    \
        /usr/lib/x86_64-linux-gnu/libopencv_imgproc.so

#作者:Shawn-HT
#来源:CSDN
#原文:https://blog.csdn.net/shawn_ht/article/details/40795039
版权声明:本文为博主原创文章,转载请附上博文链接!

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        mainwindow.cpp
HEADERS += \
        mainwindow.h
FORMS += \
        mainwindow.ui

3. 在界面.ui文件中对需要显示的部件进行布局

4. main.cpp 文件没变,主要修改mainwindow.h 和mainwindow.cpp文件

mainwindow.h 文件如下

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFileDialog>
#include <opencv2/opencv.hpp>
using namespace cv;

namespace Ui {
class MainWindow;
}
class QLabel;

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void DisplayMat(cv::Mat image);
    void mousePressEvent(QMouseEvent *event);
    //void paintEvent(QPaintEvent *event);
    bool eventFilter(QObject *watched, QEvent *event);
    Mat perspectivetransfer(Mat srcImage);

signals:
    void button_click_update();
public slots:
    void drawRedCircle();
    //void drawRedPoint(int x,int y);
    void on_actionAbout_triggered();
    void on_actionSpecifications_triggered();

private slots:
    void on_pushButton_open_clicked();

    void on_pushButton_choose_clicked(bool checked);

    void on_pushButton_perspective_clicked();

    void on_pushButton_save_clicked();

private:
    Ui::MainWindow *ui;
    cv::Mat image;
    QLabel *label;
    int count;//initial for corners order
    int point_x = 10;
    int point_y = 10;
    Point point_lt,point_rt,point_rb,point_lb;
    Mat src_resize;
    Mat save_image;
};

#endif // MAINWINDOW_H

5. mainwindow.cpp 文件如下

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <QDebug>
#include <QMessageBox>
#include <QTextCodec>
#include <QLabel>
#include <QMouseEvent>
#include <QPoint>
#include <QPainter>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowTitle(tr("Image Perspective tool-2019.03.10"));
    label = new QLabel(ui->scrollArea);
    //构造函数中注册事件过滤器
    //ui->labelimage->installEventFilter(this);
    //QObject::connect(this,SIGNAL(button_click_update()),this,SLOT(drawRedCircle()));
}

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

void MainWindow::on_actionAbout_triggered() {
    QMessageBox::about(this, tr("About ..."),tr("<h2>Image Perspective:1.0 </h2><p>Copyright 龙性的腾飞 </p>"
                                                "<p>School of Electrical and Information Engineering,Tianjin University</p>"));
}

void MainWindow::on_actionSpecifications_triggered() {
    QMessageBox::about(this, tr("Specifications"),tr("<h2>Steps as follows: </h2><p>1.Open a picture, do not contain chinese characters in the path. </p>"
                                                     "<p>2. Press 'Choose Corners' button and click four corners of the object you want to perspective transform in a clockwise. </p>"
                                                     "<p>3. Press 'Perspective Transform' button, then save the picture transformed.</p>"));
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui->labelimage && event->type() == QEvent::Paint)
        drawRedCircle();
    return QWidget::eventFilter(watched, event);

}

void MainWindow::drawRedCircle()
{
    //在label上绘制图形---->一个红色圆点
    QPainter painter(ui->labelimage);
    painter.drawLine (QPoint(0,0),QPoint(100,100));

    painter.setPen(Qt::NoPen);
    painter.setRenderHint(QPainter::Antialiasing,true);
    painter.setBrush(QColor(255,0,0));
    painter.drawLine (QPoint(0,0),QPoint(100,100));

    qDebug() << "left click";
    painter.drawEllipse(point_x,point_y,4,4);
    qDebug() << point_x;

    //update();
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    // 如果是鼠标左键按下
    //---------------------
    //作者:祥知道
    //来源:CSDN
    //原文:https://blog.csdn.net/humanking7/article/details/80707591
    //版权声明:本文为博主原创文章,转载请附上博文链接!
    if (event->button() == Qt::LeftButton && ui->lineEdit_LB->isEnabled()){
        QPoint global_pos = event->globalPos();
        QPoint label_pos = label->mapFromGlobal(global_pos);
        point_x = label_pos.x();
        point_y = label_pos.y();

        QString x = QString::number(label_pos.x(), 10);
        QString y = QString::number(label_pos.y(), 10);
        QString point = "("+x+","+y+")";
        if (ui->pushButton_choose->isChecked()){
            count += 1;
            update();
            //emit button_click_update();
            //drawRedPoint(point_x,point_y);
            switch (count) {
            case 1:
                ui->lineEdit_LT->setText(point);
                point_lt.x = label_pos.x();
                point_lt.y = label_pos.y();
                break;
            case 2:
                ui->lineEdit_RT->setText(point);
                point_rt.x = label_pos.x();
                point_rt.y = label_pos.y();
                break;
            case 3:
                ui->lineEdit_RB->setText(point);
                point_rb.x = label_pos.x();
                point_rb.y = label_pos.y();
                break;
            case 4:
                ui->lineEdit_LB->setText(point);
                point_lb.x = label_pos.x();
                point_lb.y = label_pos.y();
                break;
            }
        }
        //qDebug() << "left click"<<event->pos()<<"global:"<<event->globalPos()<<"label_pos:"<<label_pos;
    }
}

void MainWindow::on_pushButton_open_clicked()
{
    QString filename = QFileDialog::getOpenFileName(this,
                       tr("Open Image"),"/home/sun/",tr("Image File (*.jpg *.png *.bmp)"));
    qDebug()<<"filenames:"<<filename;

    QTextCodec *code = QTextCodec::codecForName("gb18030");
    std::string name = code->fromUnicode(filename).data();//filename.toAscii().data()
    image = cv::imread(name);
    QString w = QString::number(image.size().width, 10);
    QString h = QString::number(image.size().height, 10);

    QString w_h = " width: "+w+" height: "+h;
    //https://blog.csdn.net/ei__nino/article/details/7297791
    //QString s = QString::number(a, 10);             // s == "63"
    ui->statusBar->showMessage(filename+w_h);

    if(!image.data)
    {
        ui->pushButton_perspective->setEnabled(false);
        QMessageBox msgBox;
        msgBox.setText(tr("Image Data Is Null"));
        msgBox.exec();
    }
    else {
        //DisplayMat(image);
        //https://blog.csdn.net/xiezhongyuan07/article/details/79621467
        //https://blog.csdn.net/qq_37233607/article/details/79082243
        ui->pushButton_perspective->setEnabled(true);
        QImage qimage(filename);
        int q_width = qimage.size().width();
        int q_height = qimage.size().height();
        if (q_width>640 || q_height>480 )
        {
            //label = new QLabel(ui->scrollArea);
            cv::resize(image,image,Size(640,q_height*640/q_width));
            //sr= image.resize(640);
            //resize(image, src_resize, Size(640,q_height*640/q_width));
            label->setPixmap(QPixmap::fromImage(qimage).scaled(QSize(640,q_height*640/q_width),Qt::KeepAspectRatio));
            label->setAlignment(Qt::AlignTop);
            ui->scrollArea->setWidget(label);
            qDebug()<<"labelsize:"<<qimage.size();
        }
        else{
            label = new QLabel(ui->scrollArea);
            label->setPixmap(QPixmap::fromImage(qimage));
            label->setAlignment(Qt::AlignTop);
            ui->scrollArea->setWidget(label);
        }
    }
}

void MainWindow::DisplayMat(cv::Mat image)
{
    cv::Mat rgb;
    QImage img;
    if(image.channels() == 3)
    {
        cvtColor(image,rgb,CV_BGR2RGB);
        img = QImage((const unsigned char*)(rgb.data),
                     rgb.cols,rgb.rows,rgb.cols*rgb.channels(),//rgb.cols*rgb.channels()可以替换为image.step
                     QImage::Format_RGB888);
    }
    else
    {
        img = QImage((const unsigned char*)(image.data),
                     image.cols,image.rows,rgb.cols*image.channels(),
                     QImage::Format_RGB888);
    }
    QSize label_resize = QSize(image.size().width,image.size().height);
    //qDebug()<<"imagesize:"<<image.size();
    ui->labelimage->setPixmap(QPixmap::fromImage(img).scaled(label_resize));//setPixelmap(QPixmap::fromImage(img));
    ui->labelimage->resize(ui->labelimage->pixmap()->size());//resize(ui->label->pixmap()->size());
    //ui->scrollArea->setWidget(ui->labelimage);会出现崩溃,必须QLabel创建才可以
    //qDebug()<<"labelsize:"<<ui->labelimage->size();

}
//---------------------
//作者:call_me_yang
//来源:CSDN
//原文:https://blog.csdn.net/yang6464158/article/details/38109415
//版权声明:本文为博主原创文章,转载请附上博文链接!

void MainWindow::on_pushButton_choose_clicked(bool checked)
{
    if(checked){
        ui->pushButton_choose->setText("选择结束");
        count = 0;
        ui->lineEdit_LT->setEnabled(true);
        ui->lineEdit_LT->clear();
        ui->lineEdit_RT->setEnabled(true);
        ui->lineEdit_RT->clear();
        ui->lineEdit_RB->setEnabled(true);
        ui->lineEdit_RB->clear();
        ui->lineEdit_LB->setEnabled(true);
        ui->lineEdit_LB->clear();
    }
    else
    { ui->pushButton_choose->setText("选择角点"); }
}
/*void MainWindow::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    qDebug()<<"labelsize";
    QPen pen(Qt::red,5,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin);
    painter.setPen(pen);
    painter.drawLine (QPoint(0,0),QPoint(100,100));
    //must use QImage
}*/
Mat MainWindow::perspectivetransfer(Mat srcImage)
{   //选择的待变换角点
    Point2f pts_src[] = { point_lt,point_rt,point_rb,point_lb};
    //透视变换后的角点
    int height = ui->lineEdit_height->text().toInt();
    int width = ui->lineEdit_width->text().toInt();
    Point2f pts_dst[] = {Point(10, 10),Point(10+width, 10),
    Point(10+width, 10+height) ,Point(10, 10+height) };
    Mat &&M = cv::getPerspectiveTransform(pts_src, pts_dst);
    Mat warp;
    Mat PerspectivedImg(height+20, width+20, CV_8UC1);
    PerspectivedImg.setTo(0);
    cv::warpPerspective(srcImage, warp, M, PerspectivedImg.size(), cv::INTER_LINEAR , cv::BORDER_REPLICATE);
    //imshow("After Perspectived", warp);
    return warp;
}

void MainWindow::on_pushButton_perspective_clicked()
{
    save_image = perspectivetransfer(image);
    DisplayMat(save_image);
}

void MainWindow::on_pushButton_save_clicked()
{
    QString filename =QFileDialog::getSaveFileName(this,
    tr("Save Image..."),"/home/sun/deeplearning",tr("Image File (*.jpg *.png *.bmp)"));
    qDebug()<<"filenames:"<<filename;
    std::string After_perspective = filename.toStdString();
    imwrite(After_perspective,save_image);
}

6.总结

代码都是现用现查的,相关代码来源网址已附在程序中,还有以前的一些代码稍微拼了拼就出来了,由于水平有限,代码写的不是那么规范,以及操作不当会出现崩溃情况,还大家多多交流。

代码中有关于绘图的代码没有用,我也没删除,主要是开始想在点击图片选点时没点一个点可以显示一个位置红点,无奈对paintevent理解不够,一直无法实现,没再花时间搞,对变换功能影响不大。

待我有时间把代码传到github,先留个空,有问题和想法欢迎留言交流!

https://github.com/sunyuzhe2017/Perspective

猜你喜欢

转载自blog.csdn.net/qq_30460905/article/details/88383410
今日推荐