#include "TestTransform.h" #include #include #include #include using namespace cv; using namespace std; #define M_LOW_TOLERANCE 0.000001 void transPoints(vector& vec, const Matx33d& mat) { for (size_t i = 0; i < vec.size(); ++i) { Point2d p = vec[i]; Point3d tp = mat * p; vec[i] = Point2d(tp.x / tp.z, tp.y / tp.z); } } void transPoints(vector& vec, const Mat& mat) { Matx33d matx = Matx33d::eye(); Mat matx_(3, 3, CV_64FC1, matx.val); if (mat.rows == 2 && mat.cols == 3) { mat.copyTo(matx_.rowRange(0, 2)); } else if (mat.rows == 3 && mat.cols == 3) { mat.copyTo(matx_); } else { std::cout << "not supported transformation mat with its size as " \ << mat.rows << "x" << mat.cols << std::endl; return; } transPoints(vec, matx); } Matx33d affineTrans(const vector& src, const vector& dst) { if (dst.empty() || src.empty()) { return Mat(); } Point2d pc, qc; int smallerSize = src.size() < dst.size() ? src.size() : dst.size(); for (int i = 0; i < smallerSize; i++) { pc += src[i]; qc += dst[i]; } pc.x /= smallerSize; pc.y /= smallerSize; qc.x /= smallerSize; qc.y /= smallerSize; Matx21d pit; Matx12d pi; Matx12d qi; Matx22d spitpi = Matx22d::zeros(); Matx22d pitpi; Matx22d pitqi; Matx22d spitqi = Matx22d::zeros(); for (int i = 0; i < src.size() && i < dst.size(); i++) { Point2d qpi = src[i] - pc; Point2d qqi = dst[i] - qc; pit(0) = qpi.x; pit(1) = qpi.y; pi(0) = qpi.x; pi(1) = qpi.y; qi(0) = qqi.x; qi(1) = qqi.y; pitpi = pit * pi; spitpi = pitpi + spitpi; pitqi = pit * qi; spitqi = pitqi + spitqi; } Matx22d ispitpi; ispitpi = spitpi.inv(); Matx22d M = ispitpi * spitqi; double m11 = M(0, 0); double m21 = M(0, 1); double m12 = M(1, 0); double m22 = M(1, 1); Matx33d qm(m11, m12, 0, m21, m22, 0, 0, 0, 1); Matx33d pcm(1.0, 0, -pc.x, 0, 1.0, -pc.y, 0, 0, 1); Matx33d qcm(1.0, 0, qc.x, 0, 1.0, qc.y, 0, 0, 1); Matx33d ret = qcm * qm*pcm; return ret; } cv::Matx33d rigidTrans(const vector& src, const vector& dst, Mat* pCenRotScaleMat = NULL) { if (dst.empty() || src.empty()) { return Mat(); } vector weights(src.size(), 1.0 / src.size()); Point2d pc, qc; double wsum = 0; for (int i = 0; i < src.size(); i++) { double w = 1.0 / src.size(); weights[i] = w; pc += src[i] * w; qc += dst[i] * w; wsum += w; } pc.x /= wsum; pc.y /= wsum; qc.x /= wsum; qc.y /= wsum; double u = 0; double u1, u2; u1 = 0; u2 = 0; for (int i = 0; i < src.size() && i < dst.size(); i++) { Point2d qpi = src[i] - pc; Point2d qqi = dst[i] - qc; Point2d pi(qpi.x, qpi.y); Point2d qi(qqi.x, qqi.y); u1 += pi.dot(qi)*weights[i]; Point2d pi_(pi.y, -pi.x); u2 += qi.dot(pi_)*weights[i]; } u = sqrt(u1*u1 + u2 * u2); if (u < M_LOW_TOLERANCE) { u = M_LOW_TOLERANCE; } Matx22d R = Matx22d::zeros(); Matx22d r = Matx22d::zeros(); for (int i = 0; i < src.size() && i < dst.size(); i++) { Point2d qpi = src[i] - pc; Point2d qqi = dst[i] - qc; Point2d pi(qpi.x, qpi.y); Point2d qi(qqi.x, qqi.y); Point2d pi_(pi.y, -pi.x); Point2d qi_(qi.y, -qi.x); r(0, 0) = pi.dot(qi); r(0, 1) = pi.dot(qi_); r(1, 0) = pi_.dot(qi); r(1, 1) = pi_.dot(qi_); R = R + r * (weights[i] / u); } double m11 = R(0, 0); double m21 = R(0, 1); double m12 = R(1, 0); double m22 = R(1, 1); Matx33d qm(m11, m12, 0, m21, m22, 0, 0, 0, 1); Matx33d pcm(1.0, 0, -pc.x, 0, 1.0, -pc.y, 0, 0, 1); Matx33d qcm(1.0, 0, qc.x, 0, 1.0, qc.y, 0, 0, 1); Matx33d ret = qcm * qm*pcm; if (pCenRotScaleMat) { *pCenRotScaleMat = Mat(qm); } return ret; } bool cmpPointVec(const vector& vec0, const vector& vec1, const Matx33d& mat, double tor) { int smallerSize = vec0.size() < vec1.size() ? vec0.size() : vec1.size(); for (int i = 0; i < smallerSize; ++i) { Point2d p0, p1; p0 = vec0[i]; p1 = vec1[i]; Point3d tp0 = mat * p0; tp0.x /= tp0.z; tp0.y /= tp0.z; if (abs(p1.x - tp0.x) > tor || abs(p1.y - tp0.y) > tor) { return false; } } return true; } void testTransSolver() { { //rotation only vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); vec1.push_back(Point2d()); vec1.push_back(Point2d(0, 1)); vec1.push_back(Point2d(-1, 1)); vec1.push_back(Point2d(-1, 0)); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); ret = rigidTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } { // rotation and scale vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); vec1.push_back(Point2d()); vec1.push_back(Point2d(1, 1)); vec1.push_back(Point2d(0, 2)); vec1.push_back(Point2d(-1, 1)); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } { // scale only vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); vec1.push_back(Point2d()); vec1.push_back(Point2d(2, 0)); vec1.push_back(Point2d(2, 2)); vec1.push_back(Point2d(0, 2)); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } { // translation only vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); vec1.push_back(Point2d(1, 1)); vec1.push_back(Point2d(2, 1)); vec1.push_back(Point2d(2, 2)); vec1.push_back(Point2d(1, 2)); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); ret = rigidTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } { for (int i = 0; i < 10000; ++i) { // random rotation and translation Mat mat23 = getRotationMatrix2D(Point2f(), rand() % 360, 1.0); mat23.at(0, 2) = (rand() % 1000) / 1000.0; mat23.at(1, 2) = (rand() % 1000) / 1000.0; Matx33d matx = Matx33d::eye(); Mat mat(3, 3, CV_64FC1, matx.val); mat23.copyTo(mat.rowRange(0, 2)); vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); vec1 = vec0; transPoints(vec1, matx); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); ret = rigidTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } } { // skew only vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); vec1.push_back(Point2d()); vec1.push_back(Point2d(1, 0)); vec1.push_back(Point2d(2, 1)); vec1.push_back(Point2d(1, 1)); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } { // random affine for (int i = 0; i < 10000; ++i) { vector vec0, vec1; vec0.push_back(Point2d()); vec0.push_back(Point2d(1, 0)); vec0.push_back(Point2d(1, 1)); vec0.push_back(Point2d(0, 1)); Matx33d trans = Matx33d::eye(); Mat mat(3, 3, CV_64FC1, trans.val); randu(mat.rowRange(0, 2), 0, 1.0); vec1 = vec0; transPoints(vec1, trans); Matx33d ret = affineTrans(vec0, vec1); _ASSERTE(cmpPointVec(vec0, vec1, ret, M_LOW_TOLERANCE)); } } } void translate(QPolygonF srcPos, QPolygonF dstPos) { vector vec0, vec1; vec0.push_back(Point2d(srcPos.at(0).x(), srcPos.at(0).y())); vec0.push_back(Point2d(srcPos.at(1).x(), srcPos.at(1).y())); vec0.push_back(Point2d(srcPos.at(2).x(), srcPos.at(2).y())); vec0.push_back(Point2d(srcPos.at(3).x(), srcPos.at(3).y())); vec1.push_back(Point2d(dstPos.at(0).x(), dstPos.at(0).y())); vec1.push_back(Point2d(dstPos.at(1).x(), dstPos.at(1).y())); vec1.push_back(Point2d(dstPos.at(2).x(), dstPos.at(2).y())); vec1.push_back(Point2d(dstPos.at(3).x(), dstPos.at(3).y())); Matx33d ret = affineTrans(vec0, vec1); Mat retMat = Mat(ret); Point2f srcVec[4]; Point2f dstTri[4]; srcVec[0].x = srcPos.at(0).x(); srcVec[0].y = srcPos.at(0).y(); srcVec[1].x = srcPos.at(1).x(); srcVec[1].y = srcPos.at(1).y(); srcVec[2].x = srcPos.at(2).x(); srcVec[2].y = srcPos.at(2).y(); srcVec[3].x = srcPos.at(3).x(); srcVec[3].y = srcPos.at(3).y(); dstTri[0].x = dstPos.at(0).x(); dstTri[0].y = dstPos.at(0).y(); dstTri[1].x = dstPos.at(1).x(); dstTri[1].y = dstPos.at(1).y(); dstTri[2].x = dstPos.at(2).x(); dstTri[2].y = dstPos.at(2).y(); dstTri[3].x = dstPos.at(3).x(); dstTri[3].y = dstPos.at(3).y(); /// ÇóµÃ·ÂÉä±ä»» Mat warp_mat = getAffineTransform(srcVec, dstTri); double* pTransMat = (double*)(warp_mat.data); double m00=pTransMat[0]; double m10=pTransMat[1]; double m20=pTransMat[2]; double m01=pTransMat[3]; double m11=pTransMat[4]; double m21=pTransMat[5]; int newX = 100; int newY = 100; double temX = newX * m00 + newY * m10 + m20; double temY = newX * m01 + newY * m11 + m21; int a = 0; } TestTransform::TestTransform(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(onButtonClicked())); } Q_SLOT void TestTransform::onButtonClicked() { //testTransSolver(); QPolygonF srcP; srcP.append(QPointF(-105, -100)); srcP.append(QPointF(-204, -100)); srcP.append(QPointF(-300, -200)); srcP.append(QPointF(-200, -200)); QPolygonF dstP; dstP.append(QPointF(-50, 50)); dstP.append(QPointF(50, 50)); dstP.append(QPointF(50, -50)); dstP.append(QPointF(-50, -50)); translate(srcP, dstP); } void TestTransform::paintEvent(QPaintEvent *event) { QPainter painter(this); QFont font("Courier", 24); painter.setFont(font); painter.drawText(100, 100, "Hello, world!"); QTransform transform; transform.rotate(15.0); painter.setWorldTransform(transform); painter.drawText(100, 100, "Hello, world!"); }