一、基于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=;i<height;i++)
        for(int j=;j<width;j++)
        {
            if((i>=startPoint.x())&&i<endPoint.x()&&
                    (j>=startPoint.y())&&j<endPoint.y())
            {
                dstdata[i*bytesPerLine+j*]  = b;
                dstdata[i*bytesPerLine+j*+]= g;
                dstdata[i*bytesPerLine+j*+]= r;
            }
            else{
                dstdata[i*bytesPerLine+j*]  = scrdata[];
                dstdata[i*bytesPerLine+j*+]= scrdata[];
                dstdata[i*bytesPerLine+j*+]= scrdata[];
            }
            scrdata+=;
        }
    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("",this);
    y1Text = new QLineEdit("",this);
    x2Text = new QLineEdit("",this);
    y2Text = new QLineEdit("",this);
    rLabel = new QLabel("R:",this);
    gLabel = new QLabel("G:",this);
    bLabel = new QLabel("B:",this);
    rText = new QLineEdit("",this);
    gText = new QLineEdit("",this);
    bText = new QLineEdit("",this);
    okButton = new QPushButton("OK",this);
    layout->addWidget(startLabel,,,,); // 添加布局
    layout->addWidget(x1Text,,,,);
    layout->addWidget(y1Text,,,,);
    layout->addWidget(endLabel,,,,);
    layout->addWidget(x2Text,,,,);
    layout->addWidget(y2Text,,,,);
    layout->addWidget(rLabel,,,,);
    layout->addWidget(gLabel,,,,);
    layout->addWidget(bLabel,,,,);
    layout->addWidget(rText,,,,);
    layout->addWidget(gText,,,,);
    layout->addWidget(bText,,,,);
    layout->addWidget(okButton,,,,);
这样 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
如果上述教程或代码中有任何错误,欢迎批评和指证。
一、基于Qt的图像矩形区域改色的更多相关文章
- 基础的基于QT的图像查看程序
		
代码来自<QT5.9c++开发指南>,因为实现了图片的遍历显示,对于将来编写ImageShop一类的图像程序来说将非常有用(这个程序目前存在一定问题,在研究过程中进行解决) 一.基本功能 ...
 - 基于Qt的图像采集系统
		
硬件 Point Gray Camera 型号:FL3-U3-13S2C-CS 参数 Sony IMX035 CMOS, 1/3", 3.63 µm Rolling Shutter 1328 ...
 - opencv2 使用鼠标绘制矩形并截取和保存矩形区域图像
		
前言 好长时间没写博文了,今天偷偷懒写篇关于opencv2中鼠标响应操作的文章. 鼠标操作属于用户接口设计,以前一直使用Qt来做,但是如果只需要简单的鼠标,键盘操作,直接调用opencv库的函数也未尝 ...
 - 在OpenCV中利用鼠标绘制矩形和截取图像的矩形区域
		
这是两个相关的程序,前者是后者的基础.实际上前一个程序也是在前面博文的基础上做的修改,请参考<在OpenCV中利用鼠标绘制直线> .下面贴出代码. 程序之一,在OpenCV中利用鼠标绘制矩 ...
 - 基于Qt实现的截图小程序
		
在最近做的行人检测项目中,由于需要训练分类器,而分类器的训练又需要有一个一定长宽的样本.为了方便样本的采集,因此实现了这样的一个截图程序.该程序的主要功能是加载视频到程序中,程序可以对视频进行播放.暂 ...
 - Win32 GDI 非矩形区域剪裁,双缓冲技术
		
传统的Win32通过GDI提供图形显示的功能,包括了基本的绘图功能,如画线.方块.椭圆等等,高级功能包括了多边形和Bezier的绘制.这样app就不用关心那些图形学的细节了,有点类似于UNIX上的X- ...
 - Java基于opencv实现图像数字识别(四)—图像降噪
		
Java基于opencv实现图像数字识别(四)-图像降噪 我们每一步的工作都是基于前一步的,我们先把我们前面的几个函数封装成一个工具类,以后我们所有的函数都基于这个工具类 这个工具类呢,就一个成员变量 ...
 - 玩转Android Camera开发(四):预览界面四周暗中间亮,仅仅拍摄矩形区域图片(附完整源代码)
		
杂家前文曾写过一篇关于仅仅拍摄特定区域图片的demo.仅仅是比較简陋.在坐标的换算上不是非常严谨,并且没有完毕预览界面四周暗中间亮的效果,深以为憾.今天把这个补齐了. 在上代码之前首先交代下,这里面存 ...
 - HT for Web基于HTML5的图像操作(二)
		
上篇介绍了HT for Web采用HTML5 Canvas的getImageData和setImageData函数,通过颜色乘积实现的染色效果,本文将再次介绍另一种更为高效的实现方式,当然要实现的功能 ...
 
随机推荐
- NPM run start使用本地的http-server
			
在项目开发过程中,Visual Studio 2015 一个Solution中有一个前端项目 Myproject.FrontEnd,我们使用node.js, npm来进行管理 在这个项目中,有一个pa ...
 - 第四周作业-视频学习、教材作业wireshark
			
教材总结与作业 总结 网络嗅探技术定义:网络嗅探(sniff)是一种黑客常用的窃听技术,(1)利用计算机的网络接口截获目的地为其他计算机的数据报文,(2)监听数据流中所包含的用户账户密码或私密通信等. ...
 - [C++]C,C++中使用可变参数
			
可变参数即表示参数个数可以变化,可多可少,也表示参数的类型也可以变化,可以是int,double还可以是char*,类,结构体等等.可变参数是实现printf(),sprintf()等函数的关键之处, ...
 - C++ List的用法(转载)
			
Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢. assign() 给list赋值 back() 返回最后一个元素 begin ...
 - MySQL的CURRENT_DATE(),NOW(),DATE_FORMAT()函数的应用,类型转换及操作汇总
			
内容简介 datetime类型和timestamp类型的取值范围,CURRENT_DATE()函数应用,NOW()函数应用,DATE_FROMAT()函数取星期,日期.字符串.时间戳相互转换等. 时间 ...
 - CDN working principle diagram
			
转自 https://cloud.tencent.com/developer/article/1358553
 - spring定时任务的集中实现
			
转载博主:感谢博主 http://gong1208.iteye.com/blog/1773177 Spring定时任务的几种实现 近日项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前 ...
 - Domain Model
			
VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来. DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的 ...
 - vbox 挂载共享文件时可能出现的问题以及对应的解决办法
			
VMBox挂载共享文件时可能出现的问题以及对应的解决办法 如果出现“未能加载虚拟光盘***.iso 到虚拟电脑的错误” : 左边一栏,右键光盘,eject,再安装
 - postgresql 导出csv格式的数据后使用excel打开中文乱码的问题
			
两种方法: 1>使用excel 的自文本导入功能,具体方法: 1) 打开 Excel 2) 执行“数据”->“自文本” 3) 选择 CSV 文件,出现文本导入向导 4) 选择“分隔符号”, ...