一、基于Qt的图像矩形区域改色

Qt环境下图像的打开和涂色

一、设计目标

能够在 Qt QtCreator 环境下打开常用图像格式文件,诸如 bmp、jpg、png 图像等,然后将他们转化为 Qt 中的 QImage 类,并进行矩形范围内的涂色。

 

二、需要提前掌握的知识

1.Qt 图像类

Qt 中用于图像操作的类有 QImage 和 QPixmap,其中 QImage 主要负责图像编辑和修改,而 QPixmap 则负责图像的显示。

2.Qt 如何修改图像

QImage 中有一个 setPixelColor() 方法可以对image 的像素点进行操作,但是当需要操作的图像区域面积较大时,该方法的效率较低。这时最有效率的方法就是直接操作 image 在内存中的数据,可以通过 bits() 方法来获取 image 数据的首地址。

3.Qt 如何显示图像

Qt 中图像的显示主要是通过使用 QLabel 类来实现的。步骤:先打开一个图像;将图像加载进 QImage 中;在用 QPixmap 对象获得图像;最后用 QLabel 使用 setPixmap() 方法显示。

 

三、程序需求

1.一个包含打开图像,涂色功能的菜单的主窗口;

2.一个可以获取需要修改的矩形范围、颜色,并返回给主窗口的编辑对话框;

 

四、实现大致过程

1.首先实现主窗口和编辑对话框的布局;

2.分别在两个窗口中加入需要的信号和槽;

3.完成窗口内部控件以及两窗口之间的通信;

 

五、详细步骤

(一)主窗口

1.头文件

在 MainWindow 的头文件中引用头文件(Qt中使用一个类,就要引用这个类的头文件):

#include <Qlabel>

#include <QPixmap>

#include <QImage>

#include <QMenuBar>

#include <QMenu>

#include <QAction>

#include <QFileDialog>

#include <QString>

#include <QPoint>

#include <QDebug>

 

 

2.布局

在 MainWindow 的定义中加入

private:

    QLabel *label;

    QImage *image; // 全局image

    QMenuBar *menubar;

    QMenu *fileMenu;

    QMenu *editMenu;

    QAction *openAction;

    QAction *rectAction;

 

然后在MainWindow的构造函数中加入

    label = new QLabel(this);

    menubar = this->menuBar();

 

    fileMenu = menubar->addMenu("file");

    editMenu = menubar->addMenu("edit");

 

    openAction = fileMenu->addAction("openfile");

    rectAction = editMenu->addAction("rect");

 

这样,主窗口的空间布局就完成了。效果如下:

 

 

3.信号

在MianWindow的定义中加入 freshSignal 信号,该信号用于通知窗口需要更新label上的图片内容:

signals:

    void freshSignal();

 

4.槽函数

在MainWIndow的定义中加入下列槽函数:

private slots:

    void openFileSlot(); // 打开文件

    void freshSlot();  // 刷新label上的图片

    void editDialogSlot(); // 打开编辑对话框

void rectChangeSlot(QPoint,QPoint,QColor); // 修改制定rect中的像素

 

它们的实现如下:

void MainWindow::openFileSlot()

{

    QString path = QFileDialog::getOpenFileName(

                        this,

                        "文件对话框",

                        "../",//上一级路径

                        "Image(*.bmp *.jpg *.png)"

                       );

    image = new QImage(path);

 

    emit freshSignal();

}

 

void MainWindow::freshSlot()

{

    label->setPixmap(QPixmap::fromImage(*image));

 

    label->resize(image->size());

}

 

void MainWindow::editDialogSlot()

{

    editDialog->show();

}

 

void MainWindow::rectChangeSlot(QPoint startPoint,QPoint endPoint,QColor color)

{

    // Qt 打开的 bmp、jpg 图像格式为 Format_RGB32,在内存中的顺序为 B G R 0

    //    打开的 png 图像的格式为 Format_ARGB32,在内存中的顺序为 B G R A

    unsigned char *scrdata = image->bits();

    int width = image->width();

    int height = image->height();

    int bytesPerLine = image->bytesPerLine();//图像每行字节对齐

    unsigned char *dstdata = new unsigned char[bytesPerLine*height];//存储处理后的数据

 

    int r = color.red();

    int g = color.green();

    int b = color.blue();

 

    for(int i=0;i<height;i++)

        for(int j=0;j<width;j++)

        {

            if((i>=startPoint.x())&&i<endPoint.x()&&

                    (j>=startPoint.y())&&j<endPoint.y())

            {

                dstdata[i*bytesPerLine+j*4]  = b;

                dstdata[i*bytesPerLine+j*4+1]= g;

                dstdata[i*bytesPerLine+j*4+2]= r;

            }

            else{

                dstdata[i*bytesPerLine+j*4]  = scrdata[0];

                dstdata[i*bytesPerLine+j*4+1]= scrdata[1];

                dstdata[i*bytesPerLine+j*4+2]= scrdata[2];

            }

            scrdata+=4;

        }

    image= new QImage(dstdata,width,height,bytesPerLine,QImage::Format_RGB32);

 

    emit freshSignal();

}

 

5.连接信号与槽

在MainWindow的实现函数中进行连接:

connect(openAction,SIGNAL(triggered()),this,SLOT(openFileSlot()));

connect(this,SIGNAL(freshSignal()),this,SLOT(freshSlot()));

connect(rectAction,SIGNAL(triggered()),this,SLOT(editDialogSlot()));

 

这样,MainWindow 的实现就基本完成

(二)编辑对话框

1.创建编辑对话框类

编辑对话框类需要自己创建,步骤:右键项目文件夹->添加新文件->选择C++类

->选择基类为QWidget->命名为EditDialog->完成。这样工程就会自动添加两个新的文件

 

,编辑对话框创建完成。

2.头文件

在 EditDialog 的头文件中加入头文件(Qt中使用一个类,就要引用这个类的头文件):

#include <QLabel>

#include <QGridLayout>

#include <QPushButton>

#include <QLineEdit>

#include <QPoint>

 

3.布局

在 EditDialog 的定义中加入

public:

    QGridLayout *layout;

    QLabel *startLabel;

    QLabel *endLabel;

    QLineEdit *x1Text;

    QLineEdit *y1Text;

    QLineEdit *x2Text;

    QLineEdit *y2Text;

    QLabel *rLabel;

    QLabel *gLabel;

    QLabel *bLabel;

    QLineEdit *rText;

    QLineEdit *gText;

    QLineEdit *bText;

    QPushButton *okButton;

 

然后在 EditDialog 的构造函数中加入

  

  layout = new QGridLayout(this);

    startLabel = new QLabel("start",this);

    endLabel = new QLabel("end",this);

    x1Text = new QLineEdit("0",this);

    y1Text = new QLineEdit("0",this);

    x2Text = new QLineEdit("100",this);

    y2Text = new QLineEdit("100",this);

    rLabel = new QLabel("R:",this);

    gLabel = new QLabel("G:",this);

    bLabel = new QLabel("B:",this);

    rText = new QLineEdit("0",this);

    gText = new QLineEdit("0",this);

    bText = new QLineEdit("0",this);

    okButton = new QPushButton("OK",this);

 

    layout->addWidget(startLabel,0,0,1,1); // 添加布局

    layout->addWidget(x1Text,0,1,1,1);

    layout->addWidget(y1Text,0,2,1,1);

    layout->addWidget(endLabel,1,0,1,1);

    layout->addWidget(x2Text,1,1,1,1);

    layout->addWidget(y2Text,1,2,1,1);

    layout->addWidget(rLabel,2,0,1,1);

    layout->addWidget(gLabel,3,0,1,1);

    layout->addWidget(bLabel,4,0,1,1);

    layout->addWidget(rText,2,1,1,1);

    layout->addWidget(gText,3,1,1,1);

    layout->addWidget(bText,4,1,1,1);

    layout->addWidget(okButton,2,2,1,1);

 

这样 EditDialog 的布局完成,效果如下

 

 

4.信号

在 EditDialog 的定义中加入如下信号,该信号用于向 MainWindow 返回需要涂色的矩形起点和终点,并告诉 MainWIndow 执行涂色操作。

signals:

    void resultSignal(QPoint,QPoint,QColor);

 

5.槽函数

在 EditDialog 的定义中加入如下函数

public slots:

    void okButtonSlot(); // 处理案件操作

 

槽函数的实现:

void EditDialog::okButtonSlot()

{

    int x1 = x1Text->text().toInt();

    int y1 = y1Text->text().toInt();

    int x2 = x2Text->text().toInt();

    int y2 = y2Text->text().toInt();

    int r = rText->text().toInt();

    int g = gText->text().toInt();

    int b = bText->text().toInt();

    QPoint startPoint = QPoint(x1,y1);

    QPoint endPoint = QPoint(x2,y2);

    QColor color = QColor(r,g,b);

 

    emit resultSignal(startPoint,endPoint,color);

 

    this->hide();

}

 

6.连接信号与槽

在 EditDialog 的构造函数中加入

connect(okButton,SIGNAL(clicked()),this,SLOT(okButtonSlot()));

(三)主窗口与编辑对话框的连接

1.在 MainWindow 的头文件中引用头文件

#include "editdialog.h"

2.在 MainWindow 的定义中加入

EditDialog *editDialog;

3.在 MainWindow 的构造函数中加入

editDialog = new EditDialog();

4.在 MainWIndow 的构造函数中加入

connect(editDialog,SIGNAL(resultSignal(QPoint,QPoint,QColor)),this,SLOT(rectChangeSlot(QPoint,QPoint,QColor)));

至此,整个程序就编写完成,效果图如下:

 

 

github代码链接:

https://github.com/851984709/Junjie-Hu/tree/master/code/qt/task/BmpEdit

 

如果上述教程或代码中有任何错误,欢迎批评和指证。

posted @ 2018-03-09 16:30  阿卡阿卡啊卡卡卡  阅读(1265)  评论(0)    收藏  举报