-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathcvmatsurfacesource.cpp
152 lines (134 loc) · 4.03 KB
/
cvmatsurfacesource.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "cvmatsurfacesource.hpp"
#include <QAbstractVideoSurface>
#include <QThread>
#include <QDebug>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
Q_DECLARE_METATYPE(cv::Mat)
struct CVMatSurfaceSourcePrivate {
CVMatSurfaceSourcePrivate() {}
~CVMatSurfaceSourcePrivate() {}
QHash<QString, CVMatSurfaceSource *> sources;
};
Q_GLOBAL_STATIC(CVMatSurfaceSourcePrivate, g_sources)
CVMatSurfaceSource::CVMatSurfaceSource(QObject *parent) : QObject(parent),
m_surface(nullptr), m_videoFrame(nullptr)
{
}
CVMatSurfaceSource::~CVMatSurfaceSource()
{
stopSurface();
CVMatSurfaceSourcePrivate *d = g_sources;
if (d) {
d->sources.remove(m_name);
}
}
QAbstractVideoSurface *CVMatSurfaceSource::videoSurface() const
{
return m_surface;
}
void CVMatSurfaceSource::setVideoSurface(QAbstractVideoSurface *surface)
{
if (m_surface && m_surface->isActive())
m_surface->stop();
m_surface = surface;
}
void CVMatSurfaceSource::imshow(const cv::Mat &mat)
{
if (!m_surface)
return;
if (mat.empty())
return;
if (QThread::currentThread() != this->thread()) {
QVariant matVariant = QVariant::fromValue(mat.clone());
QMetaObject::invokeMethod(this, "imshowFromVariant", Qt::QueuedConnection, Q_ARG(QVariant, matVariant));
return;
}
if (!m_videoFrame) {
createVideoFrame(mat);
}
if (matHasChanged(mat)) {
if (m_videoFrame->isMapped())
m_videoFrame->unmap();
delete m_videoFrame;
createVideoFrame(mat);
}
cv::Mat matFromSurface = cv::Mat(m_videoFrame->size().height(),
m_videoFrame->size().width(),
CV_8UC4, m_videoFrame->bits());
if (mat.channels() == 3) {
cv::cvtColor(mat, matFromSurface, cv::COLOR_RGB2RGBA);
} else if (mat.channels() == 1) {
cv::cvtColor(mat, matFromSurface, cv::COLOR_GRAY2RGBA);
} else {
qDebug() << "Wrong channel count";
return;
}
if (!m_surface->present(*m_videoFrame)) {
qDebug() << "Surface present() failed" << m_surface->error();
}
}
void CVMatSurfaceSource::imshowFromVariant(const QVariant &matVariant)
{
cv::Mat mat = matVariant.value<cv::Mat>();
imshow(mat);
}
void CVMatSurfaceSource::imshow(const QString &surfaceName, const cv::Mat &mat)
{
CVMatSurfaceSourcePrivate *d = g_sources;
if (d) {
CVMatSurfaceSource *source = d->sources.value(surfaceName, nullptr);
if (source)
source->imshow(mat);
else
qWarning() << "CVMatSurfaceSource with name" << surfaceName << "doesn't exist or not yet created";
}
}
void CVMatSurfaceSource::stopSurface()
{
if (m_surface && m_surface->isActive())
m_surface->stop();
}
void CVMatSurfaceSource::createVideoFrame(const cv::Mat &mat)
{
m_videoFrame = new QVideoFrame(mat.rows * mat.cols * 4,
QSize(mat.cols, mat.rows),
mat.cols * 4,
QVideoFrame::Format_ARGB32);
m_format = QVideoSurfaceFormat(m_videoFrame->size(), m_videoFrame->pixelFormat());
m_surface->start(m_format);
if (!m_videoFrame->map(QAbstractVideoBuffer::ReadOnly)) {
qWarning() << "QVideoFrame::map() failed";
}
emit dimensionsChanged();
}
bool CVMatSurfaceSource::matHasChanged(const cv::Mat &mat) const
{
return m_videoFrame->size().width() != mat.cols ||
m_videoFrame->size().height() != mat.rows;
}
QString CVMatSurfaceSource::name() const
{
return m_name;
}
quint32 CVMatSurfaceSource::width() const
{
if (!m_format.isValid())
return 0;
return m_format.frameWidth();
}
quint32 CVMatSurfaceSource::height() const
{
if (!m_format.isValid())
return 0;
return m_format.frameHeight();
}
void CVMatSurfaceSource::setName(const QString &name)
{
CVMatSurfaceSourcePrivate *d = g_sources;
if (d) {
d->sources.remove(m_name);
d->sources.insert(name, this);
}
m_name = name;
}