1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4 
5 #include "precomp.hpp"
6 #include "intraU.hpp"
7 
8 namespace cv { namespace alphamat {
9 
findColMajorInd(int rowMajorInd,int nRows,int nCols)10 int findColMajorInd(int rowMajorInd, int nRows, int nCols)
11 {
12     int iInd = rowMajorInd / nCols;
13     int jInd = rowMajorInd % nCols;
14     return (jInd * nRows + iInd);
15 }
16 
17 static
generateFVectorIntraU(my_vector_of_vectors_t & samples,Mat & img,Mat & tmap,std::vector<int> & orig_ind)18 void generateFVectorIntraU(my_vector_of_vectors_t& samples, Mat& img, Mat& tmap, std::vector<int>& orig_ind)
19 {
20     int nRows = img.rows;
21     int nCols = img.cols;
22     int unk_count = 0;
23     int i, j;
24     for (i = 0; i < nRows; ++i)
25     {
26         for (j = 0; j < nCols; ++j)
27         {
28             uchar pix = tmap.at<uchar>(i, j);
29             if (pix == 128)
30                 unk_count++;
31         }
32     }
33     samples.resize(unk_count);
34     orig_ind.resize(unk_count);
35 
36     int c1 = 0;
37     for (i = 0; i < nRows; ++i)
38     {
39         for (j = 0; j < nCols; ++j)
40         {
41             uchar pix = tmap.at<uchar>(i, j);
42             if (pix == 128)  // collection of unknown pixels samples
43             {
44                 samples[c1].resize(ALPHAMAT_DIM);
45                 samples[c1][0] = img.at<cv::Vec3b>(i, j)[0] / 255.0;
46                 samples[c1][1] = img.at<cv::Vec3b>(i, j)[1] / 255.0;
47                 samples[c1][2] = img.at<cv::Vec3b>(i, j)[2] / 255.0;
48                 samples[c1][3] = (double(i + 1) / nRows) / 20;
49                 samples[c1][4] = (double(j + 1) / nCols) / 20;
50                 orig_ind[c1] = i * nCols + j;
51                 c1++;
52             }
53         }
54     }
55 
56     CV_LOG_INFO(NULL, "ALPHAMAT: Total number of unknown pixels : " << c1);
57 }
58 
59 static
kdtree_intraU(Mat & img,Mat & tmap,my_vector_of_vectors_t & indm,my_vector_of_vectors_t & samples,std::vector<int> & orig_ind)60 void kdtree_intraU(Mat& img, Mat& tmap, my_vector_of_vectors_t& indm, my_vector_of_vectors_t& samples, std::vector<int>& orig_ind)
61 {
62     // Generate feature vectors for intra U:
63     generateFVectorIntraU(samples, img, tmap, orig_ind);
64 
65     typedef KDTreeVectorOfVectorsAdaptor<my_vector_of_vectors_t, double> my_kd_tree_t;
66     my_kd_tree_t mat_index(ALPHAMAT_DIM /*dim*/, samples, 10 /* max leaf */);
67     mat_index.index->buildIndex();
68     // do a knn search with ku  = 5
69     const size_t num_results = 5 + 1;
70 
71     int N = samples.size();  // no. of unknown samples
72 
73     std::vector<size_t> ret_indexes(num_results);
74     std::vector<double> out_dists_sqr(num_results);
75     nanoflann::KNNResultSet<double> resultSet(num_results);
76 
77     indm.resize(N);
78     for (int i = 0; i < N; i++)
79     {
80         resultSet.init(&ret_indexes[0], &out_dists_sqr[0]);
81         mat_index.index->findNeighbors(resultSet, &samples[i][0], nanoflann::SearchParams(10));
82 
83         indm[i].resize(num_results - 1);
84         for (std::size_t j = 1; j < num_results; j++)
85         {
86             indm[i][j - 1] = ret_indexes[j];
87         }
88     }
89 }
90 
91 static
l1norm(std::vector<double> & x,std::vector<double> & y)92 double l1norm(std::vector<double>& x, std::vector<double>& y)
93 {
94     double sum = 0;
95     for (int i = 0; i < ALPHAMAT_DIM; i++)
96         sum += abs(x[i] - y[i]);
97     return sum / ALPHAMAT_DIM;
98 }
99 
100 static
intraU(Mat & img,my_vector_of_vectors_t & indm,my_vector_of_vectors_t & samples,std::vector<int> & orig_ind,SparseMatrix<double> & Wuu,SparseMatrix<double> & Duu)101 void intraU(Mat& img, my_vector_of_vectors_t& indm, my_vector_of_vectors_t& samples,
102         std::vector<int>& orig_ind, SparseMatrix<double>& Wuu, SparseMatrix<double>& Duu)
103 {
104     // input: indm, samples
105     int n = indm.size();  // num of unknown samples
106     CV_LOG_INFO(NULL, "ALPHAMAT: num of unknown samples, n : " << n);
107 
108     int i, j, nbr_ind;
109     for (i = 0; i < n; i++)
110     {
111         samples[i][3] *= 1 / 100;
112         samples[i][4] *= 1 / 100;
113     }
114 
115     my_vector_of_vectors_t weights;
116     typedef Triplet<double> T;
117     std::vector<T> triplets, td;
118 
119     double weight;
120     for (i = 0; i < n; i++)
121     {
122         int num_nbr = indm[i].size();
123         int cMaj_i = findColMajorInd(orig_ind[i], img.rows, img.cols);
124         for (j = 0; j < num_nbr; j++)
125         {
126             nbr_ind = indm[i][j];
127             int cMaj_nbr_j = findColMajorInd(orig_ind[nbr_ind], img.rows, img.cols);
128             weight = max(1 - l1norm(samples[i], samples[j]), 0.0);
129 
130             triplets.push_back(T(cMaj_i, cMaj_nbr_j, weight / 2));
131             td.push_back(T(cMaj_i, cMaj_i, weight / 2));
132 
133             triplets.push_back(T(cMaj_nbr_j, cMaj_i, weight / 2));
134             td.push_back(T(cMaj_nbr_j, cMaj_nbr_j, weight / 2));
135         }
136     }
137 
138     Wuu.setFromTriplets(triplets.begin(), triplets.end());
139     Duu.setFromTriplets(td.begin(), td.end());
140 }
141 
UU(Mat & image,Mat & tmap,SparseMatrix<double> & Wuu,SparseMatrix<double> & Duu)142 void UU(Mat& image, Mat& tmap, SparseMatrix<double>& Wuu, SparseMatrix<double>& Duu)
143 {
144     my_vector_of_vectors_t samples, indm;
145     std::vector<int> orig_ind;
146 
147     kdtree_intraU(image, tmap, indm, samples, orig_ind);
148     intraU(image, indm, samples, orig_ind, Wuu, Duu);
149     CV_LOG_INFO(NULL, "ALPHAMAT: Intra U Done");
150 }
151 
152 }}  // namespace cv::alphamat
153