QT编写简单的图像批处理工具,方便图像识别里样本图片数据处理

一、环境介绍

操作系统:windows10 X64位

QT版本: 12.6

二、软件设计需求说明

最近经常使用OpenCV等算法处理识别图像,需要准备很多正负样本图片,就编写了这个小工具,方便在处理样本数据时方便一点。软件支持灰度图像输出、支持指定的宽度、高度输出,支持保持纵横比输出。

三、效果图

四、核心代码

4.1 xxx.pro文件代码

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

RC_ICONS=log.ico

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

FORMS += \
    widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

win32
{
    message('运行win32版本')
    #添加opencv头文件的路径,需要根据自己的头文件路径进行修改
    INCLUDEPATH+=C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/include \
                 C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/include/opencv \
                 C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/include/opencv2
    LIBS+=C:/OpenCV_3.4.7/OpenCV-MinGW-Build-OpenCV-3.4.7/x86/mingw/bin/libopencv_*.dll
}

4.2  xxx.cpp代码

#include "widget.h"
#include "ui_widget.h"
class IMAGE_CONFIG image_config;

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

    this->setWindowTitle("图片格式与尺寸转换");
    /*初始化赋值*/
    dir_name="C:/"; //默认打开C盘
    save_dir_name="C:/";//默认保存到C盘
    ui->lineEdit_out_addr->setText("C:/");

    //图片的格式名字
    Format_Name="*.bmp *.jpg *.png *.ico *.JPEG *.PNG *.BMP *.ICO *.SVG *.PSD";
    ui->plainTextEdit_log->setReadOnly(true);
    ui->spinBox_high->setMaximum(2000);
    ui->spinBox_width->setMaximum(2000);
    ui->spinBox_high->setMinimum(5);
    ui->spinBox_width->setMinimum(5);
    ui->spinBox_high->setValue(480);
    ui->spinBox_width->setValue(640);
    ui->checkBox_scale->setChecked(true); //设置 纵横比默认选中
    QStringList list;
    list<<"bmp"<<"jpg"<<"png"<<"ico"<<"jpeg";
    ui->comboBox_format->addItems(list);

    //关联图片转换线程
    connect(&scale_out_image,SIGNAL(LogSend(QString)),this,SLOT(Image_Log_Display(QString)));
}


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

void Widget::Image_Log_Display(QString text)
{
    Log_Text_Display(ui->plainTextEdit_log,text);
}

/*日志显示*/
void Widget::Log_Text_Display(QPlainTextEdit *plainTextEdit_log,QString text)
{
    //设置光标到文本末尾
    plainTextEdit_log->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
    //当文本数量超出一定范围就清除
    if(plainTextEdit_log->toPlainText().size()>4096)
    {
        plainTextEdit_log->clear();
    }
    plainTextEdit_log->insertPlainText(text);
    //移动滚动条到底部
    QScrollBar *scrollbar = plainTextEdit_log->verticalScrollBar();
    if(scrollbar)
    {
        scrollbar->setSliderPosition(scrollbar->maximum());
    }
}


//选择图片
void Widget::on_pushButton_select_clicked()
{
    image_config.filenamelist=QFileDialog::getOpenFileNames(this,"选择打开的文件",dir_name,Format_Name);
    if(image_config.filenamelist.count()<=0)
    {
        Image_Log_Display("未选择任何图片.\n");
        return;
    }
    else
    {
        Image_Log_Display(tr("当前选择了%1 张图片,可以点击按钮开始转换.\n").arg(image_config.filenamelist.count()));
        QFileInfo fileinfo=QFileInfo(image_config.filenamelist.at(0)); //得到文件信息
        dir_name=fileinfo.absolutePath(); //取出绝对路径--方便下次打开
    }
}


//选择图片输出的路径
void Widget::on_pushButton_select_out_addr_clicked()
{
    save_dir_name=QFileDialog::getExistingDirectory(this,"选择目录",save_dir_name,QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);
    if(save_dir_name==nullptr)
    {
        Image_Log_Display("未选择正确路径.\n");
        ui->lineEdit_out_addr->setText("C:/");
    }
    else
    {
        ui->lineEdit_out_addr->setText(save_dir_name);
    }
}

//开始转换
void Widget::on_pushButton_Start_clicked()
{
    image_config.run_flag=1;
    image_config.high=ui->spinBox_high->value();
    image_config.width=ui->spinBox_width->value();
    image_config.isChecked=ui->checkBox_scale->isChecked();
    image_config.image_Attributes=ui->checkBox_image_Attributes->isChecked();
    image_config.comboBox_format=ui->comboBox_format->currentText();
    image_config.lineEdit_out_addr=ui->lineEdit_out_addr->text();
    //开始转换
    scale_out_image.start();
}

void Widget::on_pushButton_stop_clicked()
{
    image_config.run_flag=0;
    scale_out_image.close();
}

//关闭线程
void ScaleOutImage::close()
{
    image_config.run_flag=0;
    this->quit();
    this->wait();
}

//线程执行函数
void ScaleOutImage::run()
{
    int cnt=0;
    QString out_name;
    Mat src_frame;
    Mat dst_frame;
    for(int i=0;i<image_config.filenamelist.count();i++)
    {
        //加载图片
         QImage image(image_config.filenamelist.at(i));
         if(image.isNull())
         {
             LogSend(tr("%1 图片加载失败.\n").arg(image_config.filenamelist.at(i)));
             continue;
         }
        if(image_config.isChecked)
        {
            image=image.scaled(image_config.width,image_config.high,Qt::KeepAspectRatio, Qt::SmoothTransformation);
        }
        else
        {
            image=image.scaled(image_config.width,image_config.high);
        }

        //灰度图像
        if(image_config.image_Attributes)
        {
            // image is the input color image, img is output grey image
            for(int i = 0; i < image.width(); ++i) {
                for (int j = 0; j < image.height(); ++j) {
                    int gray = qGray(image.pixel(i, j));
                    image.setPixel(i, j, QColor(gray, gray, gray).rgb());
                }
            }


        }

        out_name=tr("%1/%2.%3").arg(image_config.lineEdit_out_addr).arg(cnt++).arg(image_config.comboBox_format);
        //判断是否转换成功
        if(image.save(out_name))
        {
            LogSend(tr("[%1] %2-->%3->成功\n").arg(i+1).arg(image_config.filenamelist.at(i)).arg(out_name));
        }
        else
        {
            LogSend(tr("[%1] %2-->%3->失败\n").arg(i+1).arg(image_config.filenamelist.at(i)).arg(out_name));
        }

        if(image_config.run_flag==0)
        {
            break;
        }
    }
}

Mat ScaleOutImage::QImage2cvMat(QImage image)
{
    Mat mat;
    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}

QImage ScaleOutImage::Mat2QImage(const Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        return QImage();
    }
}

4.3  xxx.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QPlainTextEdit>
#include <QScrollBar>
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
#include <QThread>
#include "opencv2/core/core.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

using namespace cv;

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

//图片转换
class ScaleOutImage:public QThread
{
    Q_OBJECT
public:
    void close();
    Mat QImage2cvMat(QImage image);
    QImage Mat2QImage(const Mat& mat);
protected:
    void run();
signals:
    void LogSend(QString text);
};

//全局配置
class IMAGE_CONFIG
{
   public:
    bool isChecked;  //纵横比
    bool image_Attributes; //灰度图像
    QStringList filenamelist;
    int width;
    int high;
    QString lineEdit_out_addr;
    QString comboBox_format;
    bool run_flag;
};
extern class IMAGE_CONFIG image_config;

class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void Log_Text_Display(QPlainTextEdit *plainTextEdit_log,QString text);
    QString Format_Name; //图片格式名字
    ScaleOutImage scale_out_image;
    QString dir_name; //保持当前的目录名称
    QString save_dir_name; //保存输出目录的名称
private slots:
    void Image_Log_Display(QString text);

    void on_pushButton_select_clicked();

    void on_pushButton_select_out_addr_clicked();

    void on_pushButton_Start_clicked();

    void on_pushButton_stop_clicked();

private:
    Ui::Widget *ui;
};


#endif // WIDGET_H

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章