File indexing completed on 2025-03-09 03:55:00
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 16/08/2016 0007 * Description : point transform class and its utilities that models 0008 * affine transformations between two sets of 2d-points. 0009 * 0010 * SPDX-FileCopyrightText: 2016 by Omar Amin <Omar dot moh dot amin at gmail dot com> 0011 * SPDX-FileCopyrightText: 2019 by Thanh Trung Dinh <dinhthanhtrung1996 at gmail dot com> 0012 * SPDX-FileCopyrightText: 2016-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "pointtransformaffine.h" 0019 0020 namespace Digikam 0021 { 0022 0023 PointTransformAffine::PointTransformAffine() 0024 : m(std::vector<std::vector<float> >(2, std::vector<float>(2, 0))), 0025 b(std::vector<float>(2, 0)) 0026 { 0027 m[0][0] = 1.0; 0028 m[1][1] = 1.0; 0029 } 0030 0031 PointTransformAffine::PointTransformAffine(const std::vector<std::vector<float> >& m_, 0032 const std::vector<float>& b_) 0033 : m(m_), 0034 b(b_) 0035 { 0036 } 0037 0038 PointTransformAffine::PointTransformAffine(const std::vector<std::vector<float> >& m_) 0039 : m(std::vector<std::vector<float> >(2, std::vector<float>(2, 0))), 0040 b(std::vector<float >(2, 0)) 0041 { 0042 0043 for (unsigned int i = 0 ; i < m_.size() ; ++i) 0044 { 0045 for (unsigned int j = 0 ; j < m_[0].size() ; ++j) 0046 { 0047 if (j == 2) 0048 { 0049 b[i] = m_[i][2]; 0050 } 0051 else 0052 { 0053 m[i][j] = m_[i][j]; 0054 } 0055 } 0056 } 0057 } 0058 0059 const std::vector<float> PointTransformAffine::operator() (const std::vector<float>& p) const 0060 { 0061 return (m*p + b); 0062 } 0063 0064 0065 const std::vector<std::vector<float> >& PointTransformAffine::get_m() const 0066 { 0067 return m; 0068 } 0069 0070 const std::vector<float>& PointTransformAffine::get_b() const 0071 { 0072 return b; 0073 } 0074 0075 // ---------------------------------------------------------------------------------------- 0076 0077 PointTransformAffine operator* (const PointTransformAffine& lhs, 0078 const PointTransformAffine& rhs) 0079 { 0080 return (PointTransformAffine(lhs.get_m() * rhs.get_m(), 0081 lhs.get_m() * rhs.get_b() + lhs.get_b())); 0082 } 0083 0084 // ---------------------------------------------------------------------------------------- 0085 0086 PointTransformAffine inv(const PointTransformAffine& trans) 0087 { 0088 std::vector<std::vector<float> > im = MatrixOperations::inv2(trans.get_m()); 0089 0090 return (PointTransformAffine(im, -(im * trans.get_b()))); 0091 } 0092 0093 // ---------------------------------------------------------------------------------------- 0094 0095 PointTransformAffine findSimilarityTransform(const std::vector<std::vector<float> >& fromPoints, 0096 const std::vector<std::vector<float> >& toPoints) 0097 { 0098 // We use the formulas from the paper: Least-squares estimation of transformation 0099 // parameters between two point patterns by Umeyama. They are equations 34 through 43. 0100 0101 std::vector<float> meanFrom(2, 0); 0102 std::vector<float> meanTo(2, 0); 0103 float sigmaFrom = 0.0F; 0104 float sigmaTo = 0.0F; 0105 std::vector<std::vector<float> > cov(2, std::vector<float>(2, 0)); 0106 0107 for (unsigned long i = 0 ; i < fromPoints.size() ; ++i) 0108 { 0109 meanFrom = meanFrom + fromPoints[i]; 0110 meanTo = meanTo + toPoints[i]; 0111 } 0112 0113 meanFrom = meanFrom / (int)fromPoints.size(); 0114 meanTo = meanTo / (int)fromPoints.size(); 0115 0116 for (unsigned long i = 0 ; i < fromPoints.size() ; ++i) 0117 { 0118 sigmaFrom = sigmaFrom + length_squared(fromPoints[i] - meanFrom); 0119 sigmaTo = sigmaTo + length_squared(toPoints[i] - meanTo); 0120 cov = cov + (toPoints[i] - meanTo)*(fromPoints[i] - meanFrom); 0121 } 0122 0123 sigmaFrom = sigmaFrom / (int)fromPoints.size(); 0124 sigmaTo = sigmaTo / (int)fromPoints.size(); 0125 cov = cov / (int)fromPoints.size(); 0126 (void)sigmaTo; // to silent clang scan-build 0127 0128 std::vector<std::vector<float> > u(2,std::vector<float>(2)); 0129 std::vector<std::vector<float> > v(2,std::vector<float>(2)); 0130 std::vector<std::vector<float> > vt(2,std::vector<float>(2)); 0131 std::vector<std::vector<float> > d(2,std::vector<float>(2)); 0132 std::vector<std::vector<float> > s(2,std::vector<float>(2,0)); 0133 0134 MatrixOperations::svd(cov, u, d, vt); 0135 s[0][0] = 1; 0136 s[1][1] = 1; 0137 0138 if ((MatrixOperations::determinant(cov) < 0) || 0139 ((MatrixOperations::determinant(cov) == 0) && 0140 ((MatrixOperations::determinant(u) * MatrixOperations::determinant(v)) < 0))) 0141 { 0142 if (d[1][1] < d[0][0]) 0143 { 0144 s[1][1] = -1; 0145 } 0146 else 0147 { 0148 s[0][0] = -1; 0149 } 0150 } 0151 0152 MatrixOperations::transpose(vt, v); 0153 std::vector<std::vector<float> > r = u * s * v; 0154 float c = 1.0F; 0155 0156 if (sigmaFrom != 0) 0157 { 0158 c = 1.0F / sigmaFrom * MatrixOperations::trace(d * s); 0159 } 0160 0161 std::vector<float> t = meanTo - r * meanFrom * c; 0162 0163 return (PointTransformAffine(r * c, t)); 0164 } 0165 0166 } // namespace Digikam