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

 

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