You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
439 lines
17 KiB
C++
439 lines
17 KiB
C++
/*! \file QtCVUtils.h
|
|
\brief A brief file description.
|
|
|
|
A more elaborated file description.
|
|
|
|
Created: 2014/12/30, author: ½ð±üÎÄ.
|
|
*/
|
|
#ifndef __qtcvutils_h_
|
|
#define __qtcvutils_h_
|
|
|
|
#include <opencv2/opencv.hpp>
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5,0,0))
|
|
#include <QtGui/QImage>
|
|
#include <QtGui/QPixmap>
|
|
#include <QtGui/QVector3D>
|
|
#else
|
|
#include "QImage"
|
|
#include "QPixmap"
|
|
#include "QVector3D"
|
|
#endif
|
|
#include <qlogging.h>
|
|
#include <QDebug>
|
|
#include <vector>
|
|
using namespace cv;
|
|
|
|
// std::vector to QList
|
|
template<typename Tqt, typename Tcv> static QList<Tqt> _cvqt_cast_list(const std::vector<Tcv>& v) {
|
|
QList<Tqt> ret; ret.reserve(v.size());
|
|
for (const Tcv& p : v) ret.push_back(cvqt_cast<Tqt>(p));
|
|
return ret;
|
|
}
|
|
// std::list to QList
|
|
template<typename Tqt, typename Tcv> static QList<Tqt> _cvqt_cast_list(const std::list<Tcv>& v) {
|
|
QList<Tqt> ret; ret.reserve(v.size());
|
|
for (const Tcv& p : v) ret.push_back(cvqt_cast<Tqt>(p));
|
|
return ret;
|
|
}
|
|
// QList to std::list
|
|
template<typename Tqt, typename Tcv> static std::list<Tcv> _cvqt_cast_list(const QList<Tqt>& v) {
|
|
std::list<Tcv> ret;
|
|
foreach(const Tqt& p, v) ret.push_back(cvqt_cast<Tcv>(p));
|
|
return ret;
|
|
}
|
|
// QVector to std::list
|
|
template<typename Tqt, typename Tcv> static std::list<Tcv> _cvqt_cast_list(const QVector<Tqt>& v) {
|
|
std::list<Tcv> ret;
|
|
foreach(const Tqt& p, v) ret.push_back(cvqt_cast<Tcv>(p));
|
|
return ret;
|
|
}
|
|
|
|
// std::vector to QVector
|
|
template<typename Tqt, typename Tcv> static QVector<Tqt> _cvqt_cast_vec(const std::vector<Tcv>& v) {
|
|
QVector<Tqt> ret; ret.reserve(v.size());
|
|
for (const Tcv& p : v) ret.push_back(cvqt_cast<Tqt>(p));
|
|
return ret;
|
|
}
|
|
// std::list to QVector
|
|
template<typename Tqt, typename Tcv> static QVector<Tqt> _cvqt_cast_vec(const std::list<Tcv>& v) {
|
|
QVector<Tqt> ret; ret.reserve(v.size());
|
|
for (const Tcv& p : v) ret.push_back(cvqt_cast<Tqt>(p));
|
|
return ret;
|
|
}
|
|
// QList to std::vector
|
|
template<typename Tqt, typename Tcv> static std::vector<Tcv> _cvqt_cast_vec(const QList<Tqt>& v) {
|
|
std::vector<Tcv> ret; ret.reserve(v.size());
|
|
foreach(const Tqt& p, v) ret.push_back(cvqt_cast<Tcv>(p));
|
|
return ret;
|
|
}
|
|
// QVector to std::vector
|
|
template<typename Tqt, typename Tcv> static std::vector<Tcv> _cvqt_cast_vec(const QVector<Tqt>& v) {
|
|
std::vector<Tcv> ret; ret.reserve(v.size());
|
|
foreach(const Tqt& p, v) ret.push_back(cvqt_cast<Tcv>(p));
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
#define INST_CVQT_CAST_CONTAINER(TQT, TCV)\
|
|
template<> inline QList<TQT> cvqt_cast<QList<TQT> >(const std::list<TCV>& v) { return _cvqt_cast_list<TQT, TCV>(v); }\
|
|
template<> inline QVector<TQT> cvqt_cast<QVector<TQT> >(const std::list<TCV>& v) { return _cvqt_cast_vec<TQT, TCV>(v); }\
|
|
template<> inline QList<TQT> cvqt_cast<QList<TQT> >(const std::vector<TCV>& v) { return _cvqt_cast_list<TQT, TCV>(v); }\
|
|
template<> inline QVector<TQT> cvqt_cast<QVector<TQT> >(const std::vector<TCV>& v) { return _cvqt_cast_vec<TQT, TCV>(v); }\
|
|
template<> inline std::list<TCV> cvqt_cast<std::list<TCV> >(const QList<TQT>& v) { return _cvqt_cast_list<TQT, TCV>(v);}\
|
|
template<> inline std::list<TCV> cvqt_cast<std::list<TCV> >(const QVector<TQT>& v) { return _cvqt_cast_list<TQT, TCV>(v);}\
|
|
template<> inline std::vector<TCV> cvqt_cast<std::vector<TCV> >(const QList<TQT>& v) { return _cvqt_cast_vec<TQT, TCV>(v);}\
|
|
template<> inline std::vector<TCV> cvqt_cast<std::vector<TCV> >(const QVector<TQT>& v) { return _cvqt_cast_vec<TQT, TCV>(v);}
|
|
|
|
#define DECL_CVQT_CAST_QT(TQT)\
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const TQT& v) { return Tcv(); }\
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QList<TQT>& v) { return Tcv(); }\
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QVector<TQT>& v) { return Tcv(); }
|
|
|
|
#define INSTANCE_CVQT_CAST_QT(TQT)\
|
|
template<> static inline std::vector<Point2f> cvqt_cast<std::vector<Point2f>> (const TQT& v) {\
|
|
std::vector<Point2f> ret;\
|
|
for (int i = 0; i < v.size(); ++i)\
|
|
ret.push_back(Point2f(v[i].x(), v[i].y()));\
|
|
return ret;\
|
|
}
|
|
|
|
// Points ---begin
|
|
// declarations
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QPoint& v) { return Tcv(v.x(), v.y()); }
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QPointF& v) { return Tcv(v.x(), v.y()); }
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QList<QPoint>& v) { return Tcv(); }
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QVector<QPoint>& v) { return Tcv(); }
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QList<QPointF>& v) { return Tcv(); }
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QVector<QPointF>& v) { return Tcv(); }
|
|
#define DECL_CVQT_CAST_POINT(TCV)\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const Point_<TCV>& v) { return Tqt(v.x, v.y); }\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const std::list<Point_<TCV> >& v) { return Tqt(); }\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const std::vector<Point_<TCV> >& v) { return Tqt(); }
|
|
DECL_CVQT_CAST_POINT(int) // Point2i
|
|
DECL_CVQT_CAST_POINT(float) // Point2f
|
|
DECL_CVQT_CAST_POINT(double) // Point2d
|
|
|
|
// instantiations
|
|
template<> inline QPoint cvqt_cast<QPoint>(const Point2f& v) { return QPoint(saturate_cast<int>(v.x), saturate_cast<int>(v.y)); }
|
|
template<> inline QPoint cvqt_cast<QPoint>(const Point2d& v) { return QPoint(saturate_cast<int>(v.x), saturate_cast<int>(v.y)); }
|
|
template<> inline Point2i cvqt_cast<Point2i>(const QPointF& v) { return Point2i(saturate_cast<int>(v.x()), saturate_cast<int>(v.y())); }
|
|
|
|
#define INST_CVQT_CAST_POINT(TCV)\
|
|
template<> inline QPolygon cvqt_cast<QPolygon>(const std::list<TCV>& v) { QPolygon ret; ret.reserve(v.size());\
|
|
for (const TCV& p : v) { ret << cvqt_cast<QPoint>(p); } return ret; }\
|
|
template<> inline QPolygon cvqt_cast<QPolygon>(const std::vector<TCV>& v) { QPolygon ret; ret.reserve(v.size());\
|
|
for (const TCV& p : v) { ret << cvqt_cast<QPoint>(p); } return ret; }\
|
|
template<> inline QPolygonF cvqt_cast<QPolygonF>(const std::list<TCV>& v) { QPolygonF ret; ret.reserve(v.size());\
|
|
for (const TCV& p : v) { ret << cvqt_cast<QPointF>(p); } return ret; }\
|
|
template<> inline QPolygonF cvqt_cast<QPolygonF>(const std::vector<TCV>& v) { QPolygonF ret; ret.reserve(v.size());\
|
|
for (const TCV& p : v) { ret << cvqt_cast<QPointF>(p); } return ret; }
|
|
INST_CVQT_CAST_POINT(Point2i)
|
|
INST_CVQT_CAST_POINT(Point2f)
|
|
INST_CVQT_CAST_POINT(Point2d)
|
|
|
|
// container instantiations
|
|
INST_CVQT_CAST_CONTAINER(QPoint, Point2i)
|
|
INST_CVQT_CAST_CONTAINER(QPoint, Point2f)
|
|
INST_CVQT_CAST_CONTAINER(QPoint, Point2d)
|
|
INST_CVQT_CAST_CONTAINER(QPointF, Point2i)
|
|
INST_CVQT_CAST_CONTAINER(QPointF, Point2f)
|
|
INST_CVQT_CAST_CONTAINER(QPointF, Point2d)
|
|
// Points ---end
|
|
|
|
// 3D Points ---begin
|
|
// declarations
|
|
DECL_CVQT_CAST_QT(QVector3D)
|
|
#define DECL_CVQT_CAST_3DPOINT(TCV)\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const Point3_<TCV>& v) { return Tqt(v.x, v.y, v.z); }\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const std::list<Point3_<TCV> >& v) { return Tqt(); }\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const std::vector<Point3_<TCV> >& v) { return Tqt(); }
|
|
DECL_CVQT_CAST_3DPOINT(int) // Point3i
|
|
DECL_CVQT_CAST_3DPOINT(float) // Point3f
|
|
DECL_CVQT_CAST_3DPOINT(double) // Point3d
|
|
|
|
// instantiations
|
|
#define INST_CVQT_CAST_3DPOINT(TCV)\
|
|
template<> inline QVector3D cvqt_cast<QVector3D>(const TCV& v) { return QVector3D(v.x, v.y, v.z); }\
|
|
template<> inline TCV cvqt_cast<TCV>(const QVector3D& v) { return TCV(v.x(), v.y(), v.z()); }
|
|
INST_CVQT_CAST_3DPOINT(Point3i)
|
|
INST_CVQT_CAST_3DPOINT(Point3f)
|
|
INST_CVQT_CAST_3DPOINT(Point3d)
|
|
|
|
INST_CVQT_CAST_CONTAINER(QVector3D, Point3i)
|
|
INST_CVQT_CAST_CONTAINER(QVector3D, Point3f)
|
|
INST_CVQT_CAST_CONTAINER(QVector3D, Point3d)
|
|
// 3D Points ---end
|
|
|
|
// Circle ---begin
|
|
// declarations
|
|
DECL_CVQT_CAST_QT(QPolygon)
|
|
DECL_CVQT_CAST_QT(QPolygonF)
|
|
INSTANCE_CVQT_CAST_QT(QPolygonF)
|
|
#define DECL_CVQT_CAST_VEC(TCV, CN)\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const Vec<TCV, CN>& v) { Tqt ret; for (int i = 0; i < CN; ++i) ret << v[i]; return ret; }\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const std::list<Vec<TCV, CN> >& v) { return Tqt(); }\
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const std::vector<Vec<TCV, CN> >& v) { return Tqt(); }
|
|
DECL_CVQT_CAST_VEC(int, 3) // Vec3i
|
|
DECL_CVQT_CAST_VEC(float, 3) // Vec3f
|
|
DECL_CVQT_CAST_VEC(double, 3) // Vec3d
|
|
|
|
// instantiations
|
|
#define INST_CVQT_CAST_CIRCEL(TCV)\
|
|
template<> inline QPolygon cvqt_cast<QPolygon>(const TCV& v) {\
|
|
return QPolygon() << QPoint(saturate_cast<int>(v[0]), saturate_cast<int>(v[1])) << QPoint(saturate_cast<int>(v[0]), saturate_cast<int>(v[1] + v[2])); }\
|
|
template<> inline QPolygonF cvqt_cast<QPolygonF>(const TCV& v) { return QPolygonF() << QPointF(v[0], v[1]) << QPointF(v[0], v[1] + v[2]); }\
|
|
template<> inline TCV cvqt_cast<TCV>(const QPolygon& v) { return TCV(v[0].x(), v[0].y(), std::hypot(v[0].x() - v[1].x(), v[0].y() - v[1].y())); }\
|
|
template<> inline TCV cvqt_cast<TCV>(const QPolygonF& v) { return TCV(v[0].x(), v[0].y(), std::hypot(v[0].x() - v[1].x(), v[0].y() - v[1].y())); }
|
|
INST_CVQT_CAST_CIRCEL(Vec3i)
|
|
INST_CVQT_CAST_CIRCEL(Vec3f)
|
|
INST_CVQT_CAST_CIRCEL(Vec3d)
|
|
|
|
// container instantiations
|
|
INST_CVQT_CAST_CONTAINER(QPolygon, Vec3i)
|
|
INST_CVQT_CAST_CONTAINER(QPolygon, Vec3f)
|
|
INST_CVQT_CAST_CONTAINER(QPolygon, Vec3d)
|
|
INST_CVQT_CAST_CONTAINER(QPolygonF, Vec3i)
|
|
INST_CVQT_CAST_CONTAINER(QPolygonF, Vec3f)
|
|
INST_CVQT_CAST_CONTAINER(QPolygonF, Vec3d)
|
|
// Circle ---end
|
|
|
|
// Line ---begin
|
|
// declarations
|
|
DECL_CVQT_CAST_QT(QLine)
|
|
DECL_CVQT_CAST_QT(QLineF)
|
|
DECL_CVQT_CAST_VEC(int, 4) // Vec4i
|
|
DECL_CVQT_CAST_VEC(float, 4) // Vec4f
|
|
DECL_CVQT_CAST_VEC(double, 4) // Vec4d
|
|
|
|
// instantiations
|
|
#define INST_CVQT_CAST_LINE(TCV)\
|
|
template<> inline QLine cvqt_cast<QLine>(const TCV& v) { return QLine(saturate_cast<int>(v[0]), saturate_cast<int>(v[1]),\
|
|
saturate_cast<int>(v[2]), saturate_cast<int>(v[3])); }\
|
|
template<> inline QLineF cvqt_cast<QLineF>(const TCV& v) { return QLineF(v[0], v[1], v[2], v[3]); }\
|
|
template<> inline TCV cvqt_cast<TCV>(const QLine& v) { return TCV(v.p1().x(), v.p1().y(), v.p2().x(), v.p2().y()); }\
|
|
template<> inline TCV cvqt_cast<TCV>(const QLineF& v) { return TCV(v.p1().x(), v.p1().y(), v.p2().x(), v.p2().y()); }
|
|
INST_CVQT_CAST_LINE(Vec4i)
|
|
INST_CVQT_CAST_LINE(Vec4f)
|
|
INST_CVQT_CAST_LINE(Vec4d)
|
|
|
|
// container instantiations
|
|
INST_CVQT_CAST_CONTAINER(QLine, Vec4i)
|
|
INST_CVQT_CAST_CONTAINER(QLine, Vec4f)
|
|
INST_CVQT_CAST_CONTAINER(QLine, Vec4d)
|
|
INST_CVQT_CAST_CONTAINER(QLineF, Vec4i)
|
|
INST_CVQT_CAST_CONTAINER(QLineF, Vec4f)
|
|
INST_CVQT_CAST_CONTAINER(QLineF, Vec4d)
|
|
// Line ---end
|
|
|
|
// Size ---begin
|
|
// declarations
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QSize& v) { return Tcv(v.width(), v.height()); }
|
|
template<typename Tcv> static inline Tcv cvqt_cast(const QSizeF& v) { return Tcv(v.width(), v.height()); }
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const Size& v) { return Tqt(v.width, v.height); }
|
|
template<typename Tqt> static inline Tqt cvqt_cast(const Sizef& v) { return Tqt(v.width, v.height); }
|
|
|
|
// instantiations
|
|
template<> static inline Size cvqt_cast<Size>(const QSizeF& v) { return Size(saturate_cast<int>(v.width()), saturate_cast<int>(v.height())); }
|
|
template<> static inline QSize cvqt_cast<QSize>(const Sizef& v) { return QSize(saturate_cast<int>(v.width), saturate_cast<int>(v.height)); }
|
|
// Size ---end
|
|
|
|
namespace lp
|
|
{
|
|
|
|
class QtCVUtils
|
|
{
|
|
public:
|
|
|
|
// If inImage exists for the lifetime of the resulting cv::Mat,
|
|
// pass false to inCloneImageData to share inImage's data with
|
|
// the cv::Mat directly
|
|
// NOTE: Format_RGB888 is an exception since we need to use a
|
|
// local QImage and thus must clone the data regardless
|
|
static inline cv::Mat QImageToCvMat(const QImage &inImage,
|
|
bool inCloneImageData = true)
|
|
{
|
|
switch (inImage.format())
|
|
{
|
|
// 8-bit, 4 channel
|
|
case QImage::Format_RGBA8888:
|
|
{
|
|
QImage swapped = inImage.rgbSwapped();
|
|
|
|
cv::Mat mat(swapped.height(), swapped.width(),
|
|
CV_8UC4, const_cast<uchar*>(swapped.bits()),
|
|
swapped.bytesPerLine());
|
|
|
|
return (inCloneImageData ? mat.clone() : mat);
|
|
}
|
|
case QImage::Format_ARGB32:
|
|
{
|
|
cv::Mat mat(inImage.height(), inImage.width(),
|
|
CV_8UC4, const_cast<uchar*>(inImage.bits()),
|
|
inImage.bytesPerLine());
|
|
|
|
return (inCloneImageData ? mat.clone() : mat);
|
|
}
|
|
case QImage::Format_RGB32:
|
|
{
|
|
cv::Mat mat(inImage.height(), inImage.width(),
|
|
CV_8UC4, const_cast<uchar*>(inImage.bits()),
|
|
inImage.bytesPerLine());
|
|
|
|
return (inCloneImageData ? mat.clone() : mat);
|
|
}
|
|
|
|
// 8-bit, 3 channel
|
|
case QImage::Format_RGB888:
|
|
{
|
|
if (!inCloneImageData)
|
|
qWarning() << "ASM::QImageToCvMat() - \
|
|
Conversion requires cloning since we use \
|
|
a temporary QImage";
|
|
|
|
QImage swapped = inImage.rgbSwapped();
|
|
|
|
return cv::Mat(swapped.height(), swapped.width(),
|
|
CV_8UC3, const_cast<uchar*>(swapped.bits()),
|
|
swapped.bytesPerLine()).clone();
|
|
}
|
|
|
|
// 8-bit, 1 channel
|
|
case QImage::Format_Indexed8:
|
|
{
|
|
cv::Mat mat(inImage.height(), inImage.width(),
|
|
CV_8UC1, const_cast<uchar*>(inImage.bits()),
|
|
inImage.bytesPerLine());
|
|
|
|
return (inCloneImageData ? mat.clone() : mat);
|
|
}
|
|
|
|
default:
|
|
qWarning() << "ASM::QImageToCvMat() - QImage format \
|
|
not handled in switch:" << inImage.format();
|
|
break;
|
|
}
|
|
|
|
return cv::Mat();
|
|
}
|
|
|
|
// If inPixmap exists for the lifetime of the resulting cv::Mat,
|
|
// pass false to inCloneImageData to share inPixmap's data with
|
|
// the cv::Mat directly
|
|
// NOTE: Format_RGB888 is an exception since we need to use a
|
|
// local QImage and thus must clone the data regardless
|
|
static inline cv::Mat QPixmapToCvMat(const QPixmap &inPixmap,
|
|
bool inCloneImageData = true)
|
|
{
|
|
return QImageToCvMat(inPixmap.toImage(), inCloneImageData);
|
|
}
|
|
|
|
// warning: isSwapRB should always be true, unless you do know what
|
|
// you are doing.
|
|
static inline QImage cvMatToQImage(const cv::Mat &inMat,
|
|
bool isCloneImageData = false, bool isSwapRB = true)
|
|
{
|
|
uchar* pData = NULL;
|
|
uchar* pBuffer = NULL;
|
|
QImageCleanupFunction cleanupFunc = NULL;
|
|
if (isCloneImageData)
|
|
{
|
|
pBuffer = new uchar[inMat.step*inMat.rows];
|
|
memcpy(pBuffer, inMat.data, inMat.step*inMat.rows);
|
|
cleanupFunc = [](void* p) { delete[]p; };
|
|
pData = pBuffer;
|
|
}
|
|
else
|
|
{
|
|
pData = inMat.data;
|
|
}
|
|
|
|
switch (inMat.type())
|
|
{
|
|
// 8-bit, 4 channel
|
|
case CV_8UC4:
|
|
{
|
|
QImage image(pData, inMat.cols, inMat.rows, inMat.step,
|
|
QImage::Format_RGBA8888, cleanupFunc, pBuffer);
|
|
|
|
if (isSwapRB)
|
|
{
|
|
return image.rgbSwapped();
|
|
}
|
|
else
|
|
{
|
|
return image;
|
|
}
|
|
}
|
|
|
|
// 8-bit, 3 channel
|
|
case CV_8UC3:
|
|
{
|
|
QImage image(pData, inMat.cols, inMat.rows, inMat.step,
|
|
QImage::Format_RGB888, cleanupFunc, pBuffer);
|
|
|
|
if (isSwapRB)
|
|
{
|
|
return image.rgbSwapped();
|
|
}
|
|
else
|
|
{
|
|
return image;
|
|
}
|
|
}
|
|
|
|
// 8-bit, 1 channel
|
|
case CV_8UC1:
|
|
{
|
|
static QVector<QRgb> sColorTable;
|
|
|
|
// only create our color table once
|
|
if (sColorTable.isEmpty())
|
|
{
|
|
for (int i = 0; i < 256; ++i)
|
|
sColorTable.push_back(qRgb(i, i, i));
|
|
}
|
|
|
|
QImage image(pData, inMat.cols, inMat.rows, inMat.step,
|
|
QImage::Format_Indexed8, cleanupFunc, pBuffer);
|
|
|
|
image.setColorTable(sColorTable);
|
|
|
|
return image;
|
|
}
|
|
|
|
case CV_32FC1:
|
|
{
|
|
double minVal, maxVal;
|
|
minMaxIdx(inMat, &minVal, &maxVal);
|
|
cv::Mat normedMat = (inMat - minVal) / (maxVal - minVal) * 255;
|
|
cv::Mat ret;
|
|
normedMat.convertTo(ret, CV_8UC1);
|
|
return lp::QtCVUtils::cvMatToQImage(ret, isCloneImageData);
|
|
}
|
|
|
|
default:
|
|
qWarning() << "ASM::cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type();
|
|
break;
|
|
}
|
|
|
|
return QImage();
|
|
}
|
|
|
|
static inline QPixmap cvMatToQPixmap(const cv::Mat &inMat, bool isCloneData = false)
|
|
{
|
|
return QPixmap::fromImage(cvMatToQImage(inMat, isCloneData));
|
|
}
|
|
|
|
static inline void qtRectFCenterScale(QRectF& rect, float wScale, float hScale)
|
|
{
|
|
QPointF oldCenter = rect.center();
|
|
rect.setWidth(rect.width() * wScale);
|
|
rect.setHeight(rect.height() * hScale);
|
|
rect.moveCenter(oldCenter);
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
#endif // __qtcvutils_h_
|