27 |
jakw |
1 |
#include "CodecPhaseShift.h"
|
4 |
jakw |
2 |
#include <math.h>
|
|
|
3 |
|
|
|
4 |
#include "cvtools.h"
|
|
|
5 |
|
|
|
6 |
#ifndef M_PI
|
|
|
7 |
#define M_PI 3.14159265358979323846
|
|
|
8 |
#endif
|
|
|
9 |
|
|
|
10 |
static unsigned int nPhases = 8;
|
|
|
11 |
|
|
|
12 |
// Encoder
|
|
|
13 |
static cv::Mat computePhaseVector(unsigned int length, float phase, float pitch){
|
|
|
14 |
|
|
|
15 |
cv::Mat phaseVector(length, 1, CV_8UC3);
|
|
|
16 |
//phaseVector.setTo(0);
|
|
|
17 |
|
|
|
18 |
const float pi = M_PI;
|
|
|
19 |
|
|
|
20 |
// Loop through vector
|
|
|
21 |
for(int i=0; i<phaseVector.rows; i++){
|
|
|
22 |
// Amplitude of channels
|
|
|
23 |
float amp = 0.5*(1+cos(2*pi*i/pitch + phase));
|
|
|
24 |
phaseVector.at<cv::Vec3b>(i, 0) = cv::Vec3b(255.0*amp,255.0*amp,255.0*amp);
|
|
|
25 |
}
|
|
|
26 |
|
|
|
27 |
return phaseVector;
|
|
|
28 |
}
|
|
|
29 |
|
27 |
jakw |
30 |
EncoderPhaseShift::EncoderPhaseShift(unsigned int _screenCols, unsigned int _screenRows, CodecDir _dir) : Encoder(_screenCols, _screenRows, _dir){
|
4 |
jakw |
31 |
|
|
|
32 |
// Set N
|
|
|
33 |
if(dir == CodecDirBoth)
|
|
|
34 |
this->N = 12;
|
|
|
35 |
else
|
|
|
36 |
this->N = 6;
|
|
|
37 |
|
|
|
38 |
// Precompute encoded patterns
|
|
|
39 |
const float pi = M_PI;
|
|
|
40 |
|
|
|
41 |
if(dir & CodecDirHorizontal){
|
|
|
42 |
// Horizontally encoding patterns
|
|
|
43 |
for(unsigned int i=0; i<3; i++){
|
|
|
44 |
float phase = 2.0*pi/3.0 * (1.0 - (float)i);
|
|
|
45 |
float pitch = (float)screenCols/(float)nPhases;
|
|
|
46 |
cv::Mat patternI(1,1,CV_8U);
|
|
|
47 |
patternI = computePhaseVector(screenCols, phase, pitch);
|
|
|
48 |
patternI = patternI.t();
|
|
|
49 |
patterns.push_back(patternI);
|
|
|
50 |
}
|
|
|
51 |
|
|
|
52 |
// Phase cue patterns
|
|
|
53 |
for(unsigned int i=0; i<3; i++){
|
|
|
54 |
float phase = 2.0*pi/3.0 * (1.0 - (float)i);
|
|
|
55 |
float pitch = screenCols;
|
|
|
56 |
cv::Mat patternI;
|
|
|
57 |
patternI = computePhaseVector(screenCols, phase, pitch);
|
|
|
58 |
patternI = patternI.t();
|
|
|
59 |
patterns.push_back(patternI);
|
|
|
60 |
}
|
|
|
61 |
}
|
|
|
62 |
if(dir & CodecDirVertical){
|
|
|
63 |
// Precompute vertically encoding patterns
|
|
|
64 |
for(unsigned int i=0; i<3; i++){
|
|
|
65 |
float phase = 2.0*pi/3.0 * (1.0 - (float)i);
|
|
|
66 |
float pitch = (float)screenRows/(float)nPhases;
|
|
|
67 |
cv::Mat patternI;
|
|
|
68 |
patternI = computePhaseVector(screenRows, phase, pitch);
|
|
|
69 |
patterns.push_back(patternI);
|
|
|
70 |
}
|
|
|
71 |
|
|
|
72 |
// Precompute vertically phase cue patterns
|
|
|
73 |
for(unsigned int i=0; i<3; i++){
|
|
|
74 |
float phase = 2.0*pi/3.0 * (1.0 - (float)i);
|
|
|
75 |
float pitch = screenRows;
|
|
|
76 |
cv::Mat patternI;
|
|
|
77 |
patternI = computePhaseVector(screenRows, phase, pitch);
|
|
|
78 |
patterns.push_back(patternI);
|
|
|
79 |
}
|
|
|
80 |
}
|
|
|
81 |
}
|
|
|
82 |
|
27 |
jakw |
83 |
cv::Mat EncoderPhaseShift::getEncodingPattern(unsigned int depth){
|
4 |
jakw |
84 |
return patterns[depth];
|
|
|
85 |
}
|
|
|
86 |
|
|
|
87 |
// Decoder
|
27 |
jakw |
88 |
DecoderPhaseShift::DecoderPhaseShift(CodecDir _dir) : Decoder(_dir){
|
4 |
jakw |
89 |
|
|
|
90 |
}
|
|
|
91 |
|
|
|
92 |
static cv::Mat absolutePhase(cv::Mat _I1, cv::Mat _I2, cv::Mat _I3){
|
|
|
93 |
|
|
|
94 |
const float pi = M_PI;
|
|
|
95 |
|
|
|
96 |
// Mat_ wrapper for easier indexing
|
|
|
97 |
cv::Mat_<float> I1(_I1);
|
|
|
98 |
cv::Mat_<float> I2(_I2);
|
|
|
99 |
cv::Mat_<float> I3(_I3);
|
|
|
100 |
|
|
|
101 |
cv::Mat absPhase(I1.size(), CV_32F);
|
|
|
102 |
|
|
|
103 |
for(int i = 0; i < absPhase.rows; i++){
|
|
|
104 |
for(int j = 0; j < absPhase.cols; j++){
|
|
|
105 |
float phase = atan2(sqrt(3.0) * (I1(i,j)-I3(i,j)), I1(i,j) + I3(i,j) - 2.0*I2(i,j)) + pi;
|
|
|
106 |
absPhase.at<float>(i,j) = phase;
|
|
|
107 |
}
|
|
|
108 |
}
|
|
|
109 |
|
|
|
110 |
//absPhase.addref();
|
|
|
111 |
return absPhase;
|
|
|
112 |
}
|
|
|
113 |
|
27 |
jakw |
114 |
void DecoderPhaseShift::decodeFrames(const std::vector<cv::Mat> frames, cv::Mat &up, cv::Mat &vp, cv::Mat &mask, cv::Mat &shading){
|
4 |
jakw |
115 |
|
|
|
116 |
const float pi = M_PI;
|
|
|
117 |
|
|
|
118 |
if(dir & CodecDirHorizontal){
|
|
|
119 |
std::vector<cv::Mat> framesHorz(frames.begin(), frames.begin()+6);
|
|
|
120 |
|
|
|
121 |
// Horizontal decoding
|
|
|
122 |
up = absolutePhase(framesHorz[0], framesHorz[1], framesHorz[2]);
|
|
|
123 |
|
|
|
124 |
cv::Mat upPhaseCue = absolutePhase(framesHorz[3], framesHorz[4], framesHorz[5]);
|
|
|
125 |
upPhaseCue = (upPhaseCue*nPhases-up)/(2*pi);
|
|
|
126 |
upPhaseCue.convertTo(upPhaseCue, CV_8U);
|
|
|
127 |
upPhaseCue.convertTo(upPhaseCue, CV_32F);
|
|
|
128 |
|
|
|
129 |
// unwrap absolute phase using phase cue
|
|
|
130 |
up += upPhaseCue*2*pi;
|
27 |
jakw |
131 |
|
4 |
jakw |
132 |
}
|
|
|
133 |
if(dir & CodecDirVertical){
|
|
|
134 |
std::vector<cv::Mat> framesVert(frames.end()-6, frames.end());
|
|
|
135 |
|
|
|
136 |
// Vertical decoding
|
|
|
137 |
vp = absolutePhase(framesVert[0], framesVert[1], framesVert[2]);
|
|
|
138 |
|
|
|
139 |
cv::Mat vpPhaseCue = absolutePhase(framesVert[3], framesVert[4], framesVert[5]);
|
|
|
140 |
vpPhaseCue = (vpPhaseCue*nPhases-vp)/(2*pi);
|
|
|
141 |
vpPhaseCue.convertTo(vpPhaseCue, CV_8U);
|
|
|
142 |
vpPhaseCue.convertTo(vpPhaseCue, CV_32F);
|
|
|
143 |
|
|
|
144 |
// unwrap absolute phase using phase cue
|
|
|
145 |
vp += vpPhaseCue*2*pi;
|
27 |
jakw |
146 |
|
4 |
jakw |
147 |
}
|
|
|
148 |
|
|
|
149 |
// Calculate modulation
|
|
|
150 |
cv::Mat I1, I2, I3;
|
|
|
151 |
frames[3].convertTo(I1, CV_32F);
|
|
|
152 |
frames[4].convertTo(I2, CV_32F);
|
|
|
153 |
frames[5].convertTo(I3, CV_32F);
|
|
|
154 |
cv::Mat modulation;
|
|
|
155 |
modulation = 3.0*(I1-I3).mul(I1-I3) + (2.0*I2-I1-I3).mul(2.0*I2-I1-I3);
|
|
|
156 |
cv::sqrt(modulation, modulation);
|
|
|
157 |
modulation.convertTo(shading, CV_8U);
|
|
|
158 |
//shading = (1.0/3.0)*(framesHorz[3]+framesHorz[4]+framesHorz[5]);
|
|
|
159 |
|
|
|
160 |
// Threshold modulation image for mask
|
|
|
161 |
mask = shading > 50;
|
|
|
162 |
|
|
|
163 |
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(7,7));
|
|
|
164 |
cv::erode(mask, mask, element);
|
|
|
165 |
}
|