Visual Vibration Tracking 0.2
Загрузка...
Поиск...
Не найдено
frame_handler.cpp
1#include "VVT-V2\frame_handler.h"
2
3FrameHandler::FrameHandler(const std::string input_file_name, const std::string output_file_name, const std::string main_window_name) :
4 input_cap_{ new VideoCapture(input_file_name) },
5 input_cap_status_{ false },
6 output_cap_{ new VideoWriter(output_file_name, VideoWriter::fourcc('D', 'I', 'V', 'X'), input_cap_->get(CAP_PROP_FPS), Size(input_cap_->get(CAP_PROP_FRAME_WIDTH), input_cap_->get(CAP_PROP_FRAME_HEIGHT))) },
7 main_window_name_{ main_window_name },
8 current_time_of_frame_{ 0 },
9 current_pos_of_frame_{ 0 },
10 fullscreen_{ false },
11 input_fps_{ input_cap_->get(CAP_PROP_FPS) },
12 input_frame_height_{ input_cap_->get(CAP_PROP_FRAME_HEIGHT) },
13 input_frame_width_{ input_cap_->get(CAP_PROP_FRAME_WIDTH) },
14 input_frame_size_ratio_{ input_frame_width_ / input_frame_height_ },
15 text_resize_factor_{ 1.0f }
16{
17 std::cout << "Input fps is: " << input_fps_ << std::endl;
18 // создаём окно
19 namedWindow(main_window_name_, WINDOW_NORMAL);
20
21 // Находим коэффициент масштабирования для текста
23
24 // Инициализируем текст подсказок
25 tip_text_.push_back("Default Mode");
26 tip_text_.push_back("ROI selecting mode (Press 'R')");
27 tip_text_.push_back("Pause (Press 'Space')");
28 tip_text_.push_back("Fullscreen (Press 'F')");
29}
30
31FrameHandler::~FrameHandler()
32{
33 destroyWindow(main_window_name_);
34 this->input_cap_->release();
35 delete this->input_cap_;
36 this->output_cap_->release();
37 delete this->output_cap_;
38}
40{
42 current_time_of_frame_ = input_cap_->get(CAP_PROP_POS_MSEC);
43 current_pos_of_frame_ = input_cap_->get(CAP_PROP_POS_FRAMES);
44}
45
46void FrameHandler::ShowFrame(Mat frame, bool fullscreen)
47{
48 fullscreen_ = fullscreen;
49
50 if (fullscreen_)
51 {
52 setWindowProperty(main_window_name_, WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
53 }
54 else
55 {
56 setWindowProperty(main_window_name_, WND_PROP_FULLSCREEN, WINDOW_NORMAL);
57 }
58
59 imshow(main_window_name_, frame);
60}
61
62void FrameHandler::WriteFrame(Mat frame_to_be_written)
63{
64 output_cap_->write(frame_to_be_written);
65}
66
67Mat FrameHandler::ConcatenateFramesHorizontally(Mat left_frame, Mat right_frame)
68{
69 Mat dst;
70 std::vector<Mat> vec_of_frames;
71 vec_of_frames.push_back(left_frame);
72 vec_of_frames.push_back(right_frame);
73 hconcat(vec_of_frames, dst);
74 return dst;
75}
76
77Mat FrameHandler::ConcatenateFramesVertically(Mat top_frame, Mat bottom_frame)
78{
79 Mat dst;
80 std::vector<Mat> vec_of_frames;
81 vec_of_frames.push_back(top_frame);
82 vec_of_frames.push_back(bottom_frame);
83 vconcat(vec_of_frames, dst);
84 return dst;
85}
86
87Mat FrameHandler::PutFrameOverFrame(Mat foreground_frame, Mat background_frame, Point2i translation_vector)
88{
89 // Количество каналов переднепланового изображения
90 int channels_number = foreground_frame.channels();
91 // Количества каналов двух изображений должны совпадать
92 if (channels_number != background_frame.channels())
93 return background_frame;
94
95 // Разделяем переднее изображение по каналам
96 std::vector<Mat> foreground_planes(channels_number);
97 split(foreground_frame, foreground_planes);
98
99 // Разделяем переднее изображение по каналам
100 std::vector<Mat> background_planes(channels_number);
101 split(background_frame, background_planes);
102
103 // Проходимся сначала по рядам переднего изображения (по его высоте)
104 for (int foreground_row = 0; foreground_row < foreground_frame.rows; foreground_row++)
105 {
106 // Проходимся по колонкам переднего изображения (по его ширине)
107 for (int foreground_col = 0; foreground_col < foreground_frame.cols; foreground_col++)
108 {
109 // Инициализируем значения ширины (col) и высоты (row) отображения (трансляции)
110 int translated_col = foreground_col + translation_vector.x;
111 int translated_row = foreground_row + translation_vector.y;
112
113 // Проверка, необходимая, чтобы случайно не обратиться к пикселю, находящемуся за границами фонового (заднего) изображения
114 if (!((translated_col) < background_frame.cols && (translated_row) < background_frame.rows))
115 {
116 continue;
117 }
118
119 // Итераторы для прохода по векторам каналов переднего и заднего изображений
120 auto backgnd_it = background_planes.begin();
121 auto foregnd_it = foreground_planes.begin();
122 while (backgnd_it != background_planes.end())
123 {
124 // Попиксельно отображаем (транслируем) пиксели переднего изображения на заднее изображение
125 backgnd_it->at<uchar>(translated_row, translated_col) = foregnd_it->at<uchar>(foreground_row, foreground_col);
126 backgnd_it++;
127 foregnd_it++;
128 }
129 }
130 }
131
132 Mat result;
133 merge(background_planes, result);
134 return result;
135}
136
137Mat FrameHandler::MakeGrayFrame(Mat frame_to_be_grayed)
138{
139 Mat grayed_frame;
140
141 if (!frame_to_be_grayed.empty())
142 {
143 // Конвертируем входной Mat из РГБ(БГР) в грейскейл
144 cvtColor(frame_to_be_grayed, grayed_frame, COLOR_BGR2GRAY);
145 GaussianBlur(grayed_frame, grayed_frame, Size(3, 3), 0);
146 }
147
148 return grayed_frame;
149}
150
152{
153 return input_cap_status_;
154}
155
157{
158 return current_frame_;
159}
160
162{
163 return main_window_name_;
164}
165
167{
169}
170
172{
174}
175
177{
178 return input_cap_->get(CAP_PROP_FRAME_COUNT);
179}
180
182{
183 return input_fps_;
184}
185
187{
188 return input_frame_width_;
189}
190
192{
193 return input_frame_height_;
194}
195
197{
198 return text_resize_factor_;
199}
200
201Mat FrameHandler::AddTips(Mat frame, int mode)
202{
203 // Параметры шрифта
204 int font = FONT_HERSHEY_PLAIN;
205 double font_scale = 1.5 * text_resize_factor_;
206 int thickness = 2;
207 int baseline = 0;
208 int line_spacing = 5;
209 int border_offset = 15;
210 Scalar default_tip_color(150, 150, 150);
211 Scalar mode_color(100, 255, 100);
212 // Выводим тексты подсказок для режимов
213 for (int i = 0; i < tip_text_.size() - 1; i++)
214 {
215 Scalar font_color = default_tip_color;
216 if (i == mode)
217 {
218 font_color = mode_color;
219 // Замена кнопки для переключения режимов подсвечивания точек. Пока так)
220 }
221 putText(
222 frame,
223 tip_text_[i],
224 Point2i(
225 border_offset,
226 border_offset * input_frame_size_ratio_ + i * (getTextSize(tip_text_[i], font, font_scale, thickness, &baseline).height + line_spacing)
227 ),
228 font,
229 font_scale,
230 font_color,
231 thickness,
232 4
233 );
234 }
235
236 // Выводим текст подсказки для полноэкранного режима
237 Scalar font_color = default_tip_color;
238
239 if (fullscreen_)
240 font_color = Scalar(255, 100, 100);
241 putText(
242 frame,
243 tip_text_.back(),
244 Point2i(
245 (input_frame_width_ - border_offset - (getTextSize(tip_text_.back(), font, font_scale, thickness, &baseline).width)),
246 border_offset * input_frame_size_ratio_
247 ),
248 font,
249 font_scale,
250 font_color,
251 thickness,
252 4
253 );
254
255 return frame;
256}
257
258Mat FrameHandler::GenerateGradScale(int left_limit, int right_limit, int colored_point_mode)
259{
260 // Параметры шрифта
261 int font = FONT_HERSHEY_PLAIN;
262 double font_scale = 1 * text_resize_factor_;
263 int thickness = 1;
264 int baseline = 0;
265 int font_offset = 5;
266 int font_height = getTextSize("tmp", font, font_scale, thickness, &baseline).height;
267 // Параметры окна шкалы
268 int mat_width = input_frame_width_;
269 int scale_height = 10;
270 int mat_height = scale_height + font_height + font_offset;
271 int scale_left_offset = input_frame_width_ * 0.1;
272 int scale_width = input_frame_width_ - scale_left_offset;
273
274 Mat frame = Mat(Size(mat_width, mat_height), current_frame_.type(), Scalar(0, 0, 0));
275 float interval = static_cast<float>(scale_width) / static_cast<float>(right_limit - left_limit + 1);
276 // Флаг текущей итерации
277 int iteration = 0;
278
279 // Отрисовываем цветные прямоугольнички
280 for (int x = left_limit; x <= right_limit; x++)
281 {
282 Rect scale_unit = Rect(
283 Point2f(interval * iteration + scale_left_offset, 0),
284 Point2f(interval + interval * iteration + scale_left_offset, scale_height)
285 );
286 rectangle(
287 frame,
288 scale_unit,
289 HelperFunctions::RatioToRgb(static_cast<double>(x) / static_cast<double>(right_limit)),
290 FILLED
291 );
292
293 std::string scale_signature = std::to_string(x);
294 Size current_text_size = getTextSize(scale_signature, font, font_scale, thickness, &baseline);
295
296 putText(
297 frame,
298 scale_signature,
299 Point2f(
300 scale_unit.tl().x + (interval) / 2 - current_text_size.width / 2,
301 scale_unit.br().y + scale_height + (current_text_size.height) / 2
302 ),
303 font,
304 font_scale,
305 Scalar(255, 255, 255),
306 thickness,
307 4
308 );
309
310 iteration++;
311 }
312
313 // TEMPORARY!!!
314 // Отдельно выводим два варианта режима при активном ROI - подсвечивание точек по амплитуде/частоте
315 std::string coloring_points_mode_tips[3] = { "Default", "Coloring by Frequency", "Coloring by Amplitude" };
316 Size current_text_size = getTextSize(coloring_points_mode_tips[colored_point_mode], font, font_scale, thickness, &baseline);
317
318 std::cout << "current mode: " << coloring_points_mode_tips[colored_point_mode] << std::endl;
319
320 putText(
321 frame,
322 coloring_points_mode_tips[colored_point_mode],
323 Point2f(
324 scale_left_offset / 2 - current_text_size.width / 2,
325 mat_height / 2 + current_text_size.height / 2
326 ),
327 font,
328 font_scale,
329 Scalar(255, 255, 255),
330 thickness,
331 4
332 );
333
334 return frame;
335}
336
338{
339 std::cout << "frame width: " << input_frame_width_ << std::endl;
340 std::cout << "frame height: " << input_frame_height_ << std::endl;
341
342 if (static_cast<int>(input_frame_size_ratio_))
343 {
344 switch (static_cast<int>(input_frame_height_))
345 {
346 case (480):
347 {
348 text_resize_factor_ = 0.44f;
349 break;
350 }
351 case (720):
352 {
353 text_resize_factor_ = 0.67f;
354 break;
355 }
356 case (1080):
357 {
358 text_resize_factor_ = 1.0f;
359 break;
360 }
361 case (1520):
362 {
363 text_resize_factor_ = 1.40f;
364 break;
365 }
366 case (2160):
367 {
368 text_resize_factor_ = 2.0f;
369 break;
370 }
371 }
372 }
373 else
374 {
375 switch (static_cast<int>(input_frame_width_))
376 {
377 case (480):
378 {
379 text_resize_factor_ = 0.44f;
380 break;
381 }
382 case (720):
383 {
384 text_resize_factor_ = 0.67f;
385 break;
386 }
387 case (1080):
388 {
389 text_resize_factor_ = 1.0f;
390 break;
391 }
392 case (1520):
393 {
394 text_resize_factor_ = 1.4f;
395 break;
396 }
397 case (2160):
398 {
399 text_resize_factor_ = 2.0f;
400 break;
401 }
402 }
403 }
404}
bool fullscreen_
Флаг полноэкранного режима
int GetAmountOfFrames()
Возвращает общее количество кадров
double current_time_of_frame_
Текущее время кадра из последовательности
String GetMainWindowName()
Возвращает название главного окна, в которое выводятся кадры
int GetFrameWidth()
Возвращает ширину исходного видео
Mat AddTips(Mat frame, int mode)
Добавляет (отрисовывает) подсказки для пользователя на кадр
bool GetInputCapStatus()
Возвращает текущий статус input_cap.
void ShowFrame(Mat frame, bool fullscreen)
Выводит в главное окно принимаемое изображение
FrameHandler(const std::string input_file_name, const std::string output_file_name, const std::string main_window_name)
Конструктор этого класса
Mat current_frame_
Последнний прочитанный кадр
Mat GetCurrentFrame()
Возвращает последний прочитанный на данный момент кадр
std::vector< std::string > tip_text_
Тексты подсказок для пользователя
void ReadNextFrame()
Считывает следующий кадр видео
void WriteFrame(Mat frame)
Записывает кадр с помощью output_cap.
Mat MakeGrayFrame(Mat frame_to_be_grayed)
Возвращает серый кадр с блюром
float text_resize_factor_
Коэффициент масштабирования текста (зависит от разрешения исходного видео)
double input_fps_
FPS исходного видео
VideoCapture * input_cap_
Указатель на объект-захватчик входных кадров видео
double GetCurrentTimeOfFrame()
Возвращает текущее время кадра (таймкод в мс)
bool input_cap_status_
Флаг, принимающий true при удачном чтении кадра и false, если следующий кадр не был считан
int GetInputFps()
Возвращает FPS считываемого видео
int GetCurrentPosOfFrame()
Возвращает текущее положение кадра относительно первого
Mat PutFrameOverFrame(Mat foreground_frame, Mat background_frame, Point2i translation_vector)
Накладывает изображение (переднний план) на другое изображение (задний план)
double input_frame_height_
Высота кадра исходного видео
Mat ConcatenateFramesVertically(Mat top_frame, Mat bottom_frame)
Объединяет два кадра вертикально
Mat ConcatenateFramesHorizontally(Mat left_frame, Mat right_frame)
Объединяет два кадра горизонтально
int GetFrameHeight()
Возвращает высоту считываемого видео
Mat GenerateGradScale(int left_limit, int right_limit, int colored_point_mode)
Генерирует шкалу с градиентом и подписями. Ширина шкалы - ширина исходного видео. Высота регулируется...
double input_frame_width_
Ширина кадра исходного видео
void InitTextResizeFactors()
Инициализирует коэффициент масштабирования текста в зависимости от разрешения видео
float GetTextResizeFactor()
Возвращает коэффициент масштабирования
int current_pos_of_frame_
Текущий номер кадра из последовательности
std::string main_window_name_
Имя главного окна
VideoWriter * output_cap_
Указатель на объект, сохраняющий кадры в последовательность (видео) в зависимости от выбранного кодек...
double input_frame_size_ratio_
Соотношение сторон исходного видео
cv::Scalar RatioToRgb(double ratio)
Генерирует имя TXT файла для сохранени
Definition: helper.cpp:28