-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstitch.cpp
242 lines (182 loc) · 7.59 KB
/
stitch.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*!
* @file stitch.cpp
* @brief Application used to invert and stitch two videos together frame by frame.
* Two videos are read simulataneously and the output video is a video with alternating frames from each video.
* @author D. Budihal
* @date 3/10/2018
*/
#include "opencv2/opencv.hpp"
#include <iostream>
#include <stdio.h>
#include <thread>
#include <string>
using namespace cv;
using namespace std;
#define OUTPUT_FPS 30
bool readersDone = false;
void outputVid ( Mat& readerMat1, Mat& readerMat2, bool& reader1, bool& reader2, string outputWindow, string outputFile, int frameHeight, int frameWidth)
{
cout << "Starting to write to file..." << endl;
VideoWriter vidOut(outputFile,CV_FOURCC('M','J','P','G'),OUTPUT_FPS, Size(frameWidth,frameHeight)); // create vidOut object
while(1)
{
if (readersDone == true) // if a reader is done, break out of the writing loop
break;
while (reader1 == false && readersDone == false)
{
// waiting for next Reader 1 frame...
} //wait
if (reader1 == true && readersDone == false)
{
reader1 = false; // set reader to false -> new read data needed
if (readerMat1.empty()) // break if frame is empty
break;
resize(readerMat1,readerMat1,Size(frameWidth, frameHeight)); // resize frame
vidOut.write(readerMat1); // write frame to video
// imshow( outputWindow, readerMat1 ); // display resulting frame
}
while (reader2 == false && readersDone == false)
{
// waiting for next Reader 2 frame...
} // waits
if (reader2 == true && readersDone == false)
{
reader2 = false;
if (readerMat2.empty()) // break if frame is empty
break;
resize(readerMat2,readerMat2,Size(frameWidth, frameHeight)); // resize frame
vidOut.write(readerMat2); // write frame to video
// imshow( outputWindow, readerMat2 ); // display the resulting frame
}
// Press ESC on keyboard to exit
char c = (char)waitKey(1);
if( c == 27 )
break;
}
cout << "Finished writing to output file." << endl;
}
void reader (VideoCapture& vid, Mat& readerMat, bool& reader, string vidInput)
{
cout << vidInput << " Reader Active" << endl;
while(1)
{
if (readersDone == true)
{
reader = false;
break; // stop reading because one of the videos is over
}
while (reader != false && readersDone == false)
{
// wait until writer needs a new value
}
vid >> readerMat;
bitwise_not ( readerMat, readerMat); // invert readerMat
if (readerMat.empty())
break; // stop reading because the current video is over
reader = true; // indicate that this reader's value is ready to be writter
// Press ESC on keyboard to exit
char c = (char)waitKey(1);
if( c == 27 )
break;
}
cout << "Reader is done capturing frames from " << vidInput << endl;
readersDone = true; // set readersDone flag to true because reader has finished
return;
}
int stitch (string vid1Input, string vid2Input, string vidOutput)
{
int frameHeight;
int frameWidth;
Mat readerMat1;
Mat readerMat2;
// set reader flags to false initially
bool reader1Flag = false;
bool reader2Flag = false;
VideoCapture vid1(vid1Input); // open the first test file
if(!vid1.isOpened()) // check if we succeeded
{
cout << "Video 1 File could not be successfully opened" << endl; // print error and exit
return -1;
}
VideoCapture vid2(vid2Input); // open the second test file
if(!vid2.isOpened()) // check if we succeeded
{
cout << "Video 2 File could not be successfully opened" << endl; // print error and exit
return -1;
}
// print FPS values of input videos
cout << "Video 1 FPS: " << vid1.get(CV_CAP_PROP_FPS) << endl;
cout << "Video 2 FPS: " << vid2.get(CV_CAP_PROP_FPS) << endl;
// choose frame height and frame width corresponding to the smallest dimensions present in both videos
// choose smallest frame height
if (vid1.get(CV_CAP_PROP_FRAME_HEIGHT) <= vid2.get(CV_CAP_PROP_FRAME_HEIGHT))
{
frameHeight = vid1.get(CV_CAP_PROP_FRAME_HEIGHT);
}
else
{
frameHeight = vid2.get(CV_CAP_PROP_FRAME_HEIGHT);
}
// choose smallest frame width
if (vid1.get(CV_CAP_PROP_FRAME_WIDTH) <= vid2.get(CV_CAP_PROP_FRAME_WIDTH))
{
frameWidth = vid1.get(CV_CAP_PROP_FRAME_WIDTH);
// vid2.set(CV_CAP_PROP_FRAME_WIDTH, frameWidth);
}
else
{
frameWidth = vid2.get(CV_CAP_PROP_FRAME_WIDTH);
// vid1.set(CV_CAP_PROP_FRAME_WIDTH, frameWidth);
}
cout << "Output Frame Width: " << frameWidth << endl;
cout << "Output Frame Height: " << frameHeight << endl;
cout << "Initializing thread for Video 1..." << endl;
thread read1 (reader, ref(vid1), ref(readerMat1), ref(reader1Flag), vid1Input); // spawn new thread that calls reader with Video 1 info
cout << "Initializing thread for Video 2..." << endl;
thread read2 (reader, ref(vid2), ref(readerMat2), ref(reader2Flag), vid2Input); // spawn new thread that calls reader with Video 2 info
cout << "Initializing thread for Output Video..." << endl;
thread write (outputVid, ref(readerMat1), ref(readerMat2), ref(reader1Flag), ref(reader2Flag), "Output Video", vidOutput, frameHeight, frameWidth);
// get thread IDs
thread::id id1 = read1.get_id();
thread::id id2 = read2.get_id();
thread::id id3 = write.get_id();
// // synchronize threads:
if (read1.joinable())
{
cout << "Joining thread for Video 1, ID = " << id1 << endl;
read1.join(); // pauses until read1 finishes
}
if (read2.joinable())
{
cout << "Joining thread for Video 2, ID = " << id2 << endl;
read2.join(); // pauses until read2 finishes
}
if (write.joinable())
{
cout << "Joining thread for Output Video, ID = " << id3 << endl;
write.join(); // pauses until write finishes
}
cout << "Done outputting to file" << endl;
destroyAllWindows();
return 0;
}
int main(int, char**)
{
string vid1Input = "./iris-tests/dynamic_test.mp4";
string vid2Input = "./iris-tests/field_trees.avi";
string vidOutput = "stitch.avi";
int retVal;
// Test 1
//retVal = stitch (vid1Input, vid2Input, vidOutput); // wrap function to allow for testing
// retVal = stitch("./initial-test/dynamic_test.mp4", "./initial-test/field_trees.avi", "./test-outputs/test1.avi" )
// cout << "Test 1 Return: " << retVal << endl;
// retVal = stitch ("./custom-tests/empty.avi", "./custom-tests/regular.mp4", "./test-outputs/testmp4");
// cout << "Test 2 Return: " << retVal << endl;
// retVal = stitch ("./custom-tests/pic.jpg","./custom-tests/regular.mp4", "./test-outputs/test3.avi");
// cout << "Test 3 Return: " << retVal << endl;
// retVal = stitch ("./custom-tests/null.avi","./custom-tests/null.avi", "./test-outputs/test4.avi");
// cout << "Test 4 Return: " << retVal << endl;
retVal = stitch ("./custom-tests/large.mp4","./custom-tests/regular.mp4", "./test-outputs/test5.avi");
cout << "Test 5 Return: " << retVal << endl;
return retVal;
}