一个显示 OpenCV Mat 图像的自定义 Qt 控件
今天学习 Qt 的时候顺手写了一个,包含一个头文件 qcvdisplay.h 和一个源文件 qcvdisplay.cpp,因为这是 qt 默认的文件命名方式,在 Qt Designer 中提升控件时会省去输入文件名的步骤,所以最好不要改名。
qcvdisplay.h :
#ifndef QCVDISPLAY_H
#define QCVDISPLAY_H #include <QWidget>
#include <QException>
#include <opencv2/core/core.hpp> // 当图片不是灰度图或者 BGR 图像时抛出此异常
class UnsupportedFormatError : public QException
{
public:
void raise() const { throw *this; }
UnsupportedFormatError *clone() const { return new UnsupportedFormatError(*this); }
}; // 显示 opencv 图片的自定义控件
class QCVDisplay : public QWidget
{
Q_OBJECT
public:
explicit QCVDisplay(QWidget *parent = );
cv::Mat getBuffer(); public slots:
void displayImage(const cv::Mat& img); protected:
void matToQImage(const cv::Mat3b &src, QImage &dest);
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
QImage data;
cv::Mat buffer;
}; #endif // QCVDISPLAY_H
qcvdisplay.cpp
#include "qcvdisplay.h" #include <QResizeEvent>
#include <QPaintEvent>
#include <QPainter> #include <opencv2/imgproc/imgproc.hpp> QCVDisplay::QCVDisplay(QWidget *parent) :
QWidget(parent)
{
} cv::Mat QCVDisplay::getBuffer()
{
return buffer;
} // 将 Mat 转换为 QImage,由于 QImage 的每一行有多余对齐字节
// 故采用 RBG32 来消除多余字节
void QCVDisplay::matToQImage(const cv::Mat3b &src, QImage& dest)
{
for (int y = ; y < src.rows; ++y) {
const cv::Vec3b *srcrow = src[y];
QRgb *destrow = (QRgb*)dest.scanLine(y);
for (int x = ; x < src.cols; ++x) {
destrow[x] = qRgba(srcrow[x][], srcrow[x][], srcrow[x][], );
}
}
} // 在控件上显示图片,使用 opencv 自带的 resize 使其缩放到和控件大小一致
void QCVDisplay::displayImage(const cv::Mat &img)
{
QSize sz = data.size();
if (img.channels() == ) {
buffer = img.clone();
} else if (img.channels() == ) {
cv::cvtColor(img, buffer, CV_GRAY2RGB);
} else {
throw UnsupportedFormatError();
}
cv::Mat resized;
if (!sz.isEmpty()) {
cv::resize(buffer, resized, cv::Size(sz.width(), sz.height()));
matToQImage(resized, data);
update();
}
} // 绘图事件处理函数
void QCVDisplay::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.drawImage(event->rect(), data, event->rect());
} // 缩放事件也采用 opencv 自带的 resize
void QCVDisplay::resizeEvent(QResizeEvent *event)
{
if (data.size() != event->size()) {
cv::Mat resized;
data = QImage(event->size(), QImage::Format_RGB32);
if (!buffer.empty() && !event->size().isEmpty()) {
cv::resize(buffer, resized, cv::Size(event->size().width(),
event->size().height()));
matToQImage(resized, data);
}
}
QWidget::resizeEvent(event);
}
实现的思路很直接,重写 paintEvent 和 resizeEvent 两个事件处理函数来进行控件的自定义显示,用一个 Mat 作为原始图片的缓存(buffer),将其调整到与空间大小一致后再显示。QImage 的格式选择 RGB32 (第一个字节为 0xFF),使得图像每一行的像素个数全部都是 4 的倍数,消除多余的对齐像素,避免图片在显示时变形。(OpenCV 2.0 以后的图片已经不存在对齐像素了,即图像数据在内存中是连续的)
使用时将两个文件加入当前项目,在 Qt Designer 中拖入一个 widget 基类,在 widget 上点右键,选择 “提升为...”,在弹出的对话框中按照下图输入。

输入完提升的类名称,点击添加,提升即可。
一个显示 OpenCV Mat 图像的自定义 Qt 控件的更多相关文章
- 【Android开发日记】之入门篇(十四)——Button控件+自定义Button控件
好久不见,又是一个新的学期开始了,为什么我感觉好惆怅啊!这一周也发生了不少事情,节假日放了三天的假(好久没有这么悠闲过了),实习公司那边被组长半强制性的要求去解决一个后台登陆的问题,结果就是把 ...
- 自定义SWT控件一之自定义单选下拉框
一.自定义下拉控件 自定义的下拉框,是自定义样式的,其中的下拉框使用的是独立的window,非复选框的下拉框双击单机其它区域或选择完之后,独立window构成的下拉框会自动消失. package co ...
- Android自定义控件之自定义组合控件
前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...
- C# DataGridView自定义分页控件
好些日子不仔细写C#代码了,现在主要是Java项目,C#.Net相关项目不多了,有点手生了,以下代码不足之处望各位提出建议和批评. 近日闲来无事想研究一下自定义控件,虽然之前也看过,那也仅限于皮毛,粗 ...
- C# 自定义FileUpload控件
摘要:ASP.NET自带的FileUpload控件会随着浏览器的不同,显示的样式也会发生改变,很不美观,为了提高用户体验度,所以我们会去自定义FileUpload控件 实现思路:用两个Button和T ...
- (九)ASP.NET自定义用户控件(2)
http://www.cnblogs.com/SkySoot/archive/2012/09/04/2670678.html 用户控件 在 .NET 里,可以通过两种方式把自己的控件插入到 Web 窗 ...
- (八)ASP.NET自定义用户控件(1)
http://blog.csdn.net/laodao1/article/details/5897366 ASP.NET自定义控件组件开发 第一章:从一个简单的控件谈起 起始开发ASP.NET自定义控 ...
- 【转】带checkbox的ListView实现(二)——自定义Checkable控件的实现方法
原文网址:http://blog.csdn.net/harvic880925/article/details/40475367 前言:前一篇文章给大家展示了传统的Listview的写法,但有的时候我们 ...
- Qt控件精讲一:按钮
原地址:http://blog.csdn.net/yuxikuo_1/article/details/17397109 Qt Creater提供6种Button控件.如图1. Button控件介绍 控 ...
随机推荐
- 跨IDC ycache原理和配置说明
总体介绍: 多idc缓存方案的invalid方案(如下图),是通过两个操作保证多个idc之间的缓存的高可用性和最终一致性的. 更新数据库后,发送invalid消息:invalid消息广播到其他id ...
- leetcode-easy-trees-102. Binary Tree Level Order Traversal-YES
mycode 98.56% # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x ...
- [Java]算术表达式求值之一(中序表达式转后序表达式方案)
第二版请见:https://www.cnblogs.com/xiandedanteng/p/11451359.html 入口类,这个类的主要用途是粗筛用户输入的算术表达式: package com.h ...
- tomcat 日志拆分
一.用cronolog分割tomcat的catalina.out文件 1.编译安装cronologwget http://cronolog.org/download/cronolog-1.6.2.ta ...
- Jmeter (四)聚合报告详解
- 阶段3 2.Spring_07.银行转账案例_5 编写业务层和持久层事务控制代码并配置spring的ioc
Service中就需要用到 TransactionManager中的方法.提供set方法等着spring注入 这里面所有的操作都可以加上事物控制 其他的方法都是相同的操作 这里没有返回结果 转账的方法 ...
- python之reportlab生成PDF文件
项目需要,需要自动生成PDF测试报告.经过对比之后,选择使用了reportlab模块. 项目背景:开发一个测试平台,供测试维护测试用例,执行测试用例,并且生成测试报告(包含PDF和excel),将生成 ...
- qrcode-reader——二维码识别
JavaScript QRCode reader for HTML5 enabled browser 参考资料1:[https://www.npmjs.com/package/qrcode-reade ...
- C++ 优先队列 priority_queue
平时定义的时候,直接上就完事了: priority_queue<int>Q; 默认大根堆. 之前很菜的时候不知道小根堆怎么写,还在考场上干过加个负号甩到大根堆里面去的蠢事. 它的完整形式呢 ...
- kafka语句示例
1.从http://kafka.apache.org/下载kafka安装包:2.tar zxvf kafka_2.8.0.tar.gz,修改配置文件conf/server.properties:bro ...