
\documentclass[a4paper, final]{article}
\usepackage[14pt]{extsizes} % для того чтобы задать нестандартный 14-ый размер шрифта
\usepackage[T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[russian]{babel}
\usepackage{ragged2e}
\usepackage{algorithmic}
\usepackage{amsmath}
\usepackage{multicol}
\usepackage{nccmath}
\usepackage{tikz}
\usepackage{wrapfig}
\usepackage{caption}
\usepackage{tabularx}
\usepackage{array}
\usepackage[left=25mm, top=20mm, right=20mm, bottom=20mm, footskip=10mm]{geometry}
\usepackage{ragged2e} %для растягивания по ширине
\usepackage{setspace} %для межстрочного интервала
\usepackage{moreverb} %для работы с листингами
\usepackage{indentfirst} % для абзацного отступа
\usepackage{moreverb} %для печати в листинге исходного кода программ
\renewcommand\verbatimtabsize{4\relax}
\renewcommand\listingoffset{0.2em}
\renewcommand{\arraystretch}{1.4} % изменяю высоту строки в таблице
\usepackage[font=small, singlelinecheck=false, justification=raggedleft, format=plain, labelsep=period]{caption} %для настройки заголовка таблицы
%\usepackage[dvips]{graphicx} % Для вставки графических изображений
%\usepackage{color} %% это для отображения цвета в коде
%\usepackage{xcolor} % цвета
\usepackage{listingsutf8}
\usepackage{hyperref}% для гиперссылок
\usepackage{enumitem} %для перечислений
\usepackage{pdflscape} %для pdf
\usepackage{pdfpages} %для pdf

\definecolor{apricot}{HTML}{FFF0DA}
\definecolor{mygreen}{rgb}{0,0.6,0}
\definecolor{string}{HTML}{B40000} % цвет строк в коде
\definecolor{comment}{HTML}{008000} % цвет комментариев в коде
\definecolor{keyword}{HTML}{1A00FF} % цвет ключевых слов в коде
\definecolor{morecomment}{HTML}{8000FF} % цвет include и других элементов в коде
\definecolor{captiontext}{HTML}{FFFFFF} % цвет текста заголовка в коде
\definecolor{captionbk}{HTML}{999999} % цвет фона заголовка в коде
\definecolor{bk}{HTML}{FFFFFF} % цвет фона в коде
\definecolor{frame}{HTML}{999999} % цвет рамки в коде
\definecolor{brackets}{HTML}{B40000} % цвет скобок в коде

\setlist[enumerate,itemize]{leftmargin=1.2cm}

\hypersetup{colorlinks,
	pdftitle={Лабораторная №3},
	pdfauthor={Тищенко А. А.},
	allcolors=[RGB]{010 090 200}}
% подгружаемые языки — подробнее в документации listings
\lstloadlanguages{bash}
% включаем кириллицу и добавляем кое−какие опции
%\lstset{language =[LaTeX] TeX, % выбираем язык по умолчанию
	%extendedchars=true , % включаем не латиницу
	%escapechar = | , % |«выпадаем» в LATEX|
	%frame=tb , % рамка сверху и снизу
	%commentstyle=\itshape , % шрифт для комментариев
	%stringstyle =\bfseries} % шрифт для строк

\textheight=24cm % высота текста
\textwidth=16cm % ширина текста
\oddsidemargin=0pt % отступ от левого края
\topmargin=-1.5cm % отступ от верхнего края
\parindent=24pt % абзацный отступ
\parskip=0pt % интервал между абзацами
\tolerance=2000 % терпимость к "жидким" строкам
\flushbottom % выравнивание высоты страниц

\addto\captionsrussian{\def\refname{\hspace{1.15cm} Список литературы}}

\begin{document} % начало документа
	
	\lstset{
		language=Python, % Язык кода по умолчанию
		morekeywords={*,...}, % если хотите добавить ключевые слова, то добавляйте
		% Цвета
		keywordstyle=\color{keyword}\ttfamily\bfseries,
		%stringstyle=\color{string}\ttfamily,
		stringstyle=\ttfamily\color{red!50!brown},
		commentstyle=\color{comment}\ttfamily,
		morecomment=[l][\color{morecomment}]{\#},
		% Настройки отображения
		breaklines=true, % Перенос длинных строк
		basicstyle=\ttfamily\footnotesize, % Шрифт для отображения кода
		backgroundcolor=\color{bk}, % Цвет фона кода
		frame=lrb,xleftmargin=\fboxsep,xrightmargin=-\fboxsep, % Рамка, подогнанная к заголовку
		rulecolor=\color{frame}, % Цвет рамки
		tabsize=3, % Размер табуляции в пробелах
		% Настройка отображения номеров строк. Если не нужно, то удалите весь блок
		numbers=left, % Слева отображаются номера строк
		stepnumber=1, % Каждую строку нумеровать
		numbersep=5pt, % Отступ от кода
		numberstyle=\small\color{black}, % Стиль написания номеров строк
		% Для отображения русского языка
		extendedchars=true,
		literate={Ö}{ {\"O} }1
		{~}{ {\textasciitilde} }1
		{а}{ {\selectfont\char224} }1
		{б}{ {\selectfont\char225} }1
		{в}{ {\selectfont\char226} }1
		{г}{ {\selectfont\char227} }1
		{д}{ {\selectfont\char228} }1
		{е}{ {\selectfont\char229} }1
		{ё}{ {\"e} }1
		{ж}{ {\selectfont\char230} }1
		{з}{ {\selectfont\char231} }1
		{и}{ {\selectfont\char232} }1
		{й}{ {\selectfont\char233} }1
		{к}{ {\selectfont\char234} }1
		{л}{ {\selectfont\char235} }1
		{м}{ {\selectfont\char236} }1
		{н}{ {\selectfont\char237} }1
		{о}{ {\selectfont\char238} }1
		{п}{ {\selectfont\char239} }1
		{р}{ {\selectfont\char240} }1
		{с}{ {\selectfont\char241} }1
		{т}{ {\selectfont\char242} }1
		{у}{ {\selectfont\char243} }1
		{ф}{ {\selectfont\char244} }1
		{х}{ {\selectfont\char245} }1
		{ц}{ {\selectfont\char246} }1
		{ч}{ {\selectfont\char247} }1
		{ш}{ {\selectfont\char248} }1
		{щ}{ {\selectfont\char249} }1
		{ъ}{ {\selectfont\char250} }1
		{ы}{ {\selectfont\char251} }1
		{ь}{ {\selectfont\char252} }1
		{э}{ {\selectfont\char253} }1
		{ю}{ {\selectfont\char254} }1
		{я}{ {\selectfont\char255} }1
		{А}{ {\selectfont\char192} }1
		{Б}{ {\selectfont\char193} }1
		{В}{ {\selectfont\char194} }1
		{Г}{ {\selectfont\char195} }1
		{Д}{ {\selectfont\char196} }1
		{Е}{ {\selectfont\char197} }1
		{Ё}{ {\"E} }1
		{Ж}{ {\selectfont\char198} }1
		{З}{ {\selectfont\char199} }1
		{И}{ {\selectfont\char200} }1
		{Й}{ {\selectfont\char201} }1
		{К}{ {\selectfont\char202} }1
		{Л}{ {\selectfont\char203} }1
		{М}{ {\selectfont\char204} }1
		{Н}{ {\selectfont\char205} }1
		{О}{ {\selectfont\char206} }1
		{П}{ {\selectfont\char207} }1
		{Р}{ {\selectfont\char208} }1
		{С}{ {\selectfont\char209} }1
		{Т}{ {\selectfont\char210} }1
		{У}{ {\selectfont\char211} }1
		{Ф}{ {\selectfont\char212} }1
		{Х}{ {\selectfont\char213} }1
		{Ц}{ {\selectfont\char214} }1
		{Ч}{ {\selectfont\char215} }1
		{Ш}{ {\selectfont\char216} }1
		{Щ}{ {\selectfont\char217} }1
		{Ъ}{ {\selectfont\char218} }1
		{Ы}{ {\selectfont\char219} }1
		{Ь}{ {\selectfont\char220} }1
		{Э}{ {\selectfont\char221} }1
		{Ю}{ {\selectfont\char222} }1
		{Я}{ {\selectfont\char223} }1
		{\{}{ { {\color{brackets}\{} } }1 % Цвет скобок {
			{\} }{ { {\color{brackets}\} } } }1 % Цвет скобок }
	}
	
	
	% НАЧАЛО ТИТУЛЬНОГО ЛИСТА
	\thispagestyle{empty}
	\begin{center}
		\normalsize{МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ \\ ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ АВТОНОМНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО \\ ОБРАЗОВАНИЯ\\ «Санкт-Петербургский политехнический университет Петра Великого»}
		\normalsize{Институт компьютерных наук и кибербезопасности}\\[10pt]
		\normalsize{Высшая школа технологий искусственного интеллекта}\\[10pt]
		\normalsize{Направление: 02.03.01 Математика и компьютерные науки}\\
		\hfill \break
		\hfill \break
		\hfill \break
		\hfill \break
		\hfill \break
		\hfill \break
		\normalsize{Отчет о выполнении лабораторной работы №3 по дисциплине}\\[3pt]
		\normalsize{«Алгоритмические основы компьютерной графики»}\\[3pt]
		\normalsize{по теме:}\\[3pt]
		\normalsize{«Визуализация физического процесса»}\\[10pt]
	\end{center}
	\hfill \break
	\hfill \break
	\hfill \break
	\hfill \break
	\begin{tabular}{lcrl}	
		\!\!\!Студент, & \hspace{2cm} & & \\
		\!\!\!группы 5130201/20101 & \hspace{2.13cm} & \underline{\hspace{3cm}} &Тищенко А. А. \\\\
		\!\!\!Преподаватель & \hspace{2cm}  & \underline{\hspace{3cm}} & Курочкин М. А. \\\\
		&&\hspace{5cm}
		
	\end{tabular} 	
	\begin{flushright}
		<<\underline{\hspace{1cm}}>>\underline{\hspace{2.5cm}} 2025 г.
	\end{flushright}
	\hfill \break  
	\hfill \break
	\begin{center} \small{Санкт-Петербург, 2025} \end{center}
	\newpage %Содержание% выключаем отображение номера для этой страницы
	
	% КОНЕЦ ТИТУЛЬНОГО ЛИСТА
	
	\newpage
	
	\tableofcontents
	
	% \newpage
	% \addcontentsline{toc}{section}{Введение}
	
	% \newpage
	% \subsection*{Введение}

	% Компьютерная графика служит мощным средством для отображения физических явлений, обеспечивая возможность их визуализации и изучения динамических свойств. Одним из значимых направлений в этой области является визуализация жидкостей, которая позволяет имитировать реальные физические явления, в частности, движение воды.
	
	
	
	% Процедурные методы визуализации занимают особую нишу среди подходов к созданию графики, поскольку их принцип основан на применении математических алгоритмов и физических закономерностей. В отличие от традиционного подхода, требующего ручной работы над каждым кадром, процедурные методы автоматизируют генерацию изменений, что делает их оптимальными для воспроизведения таких сложных систем, как:
	
	% \begin{itemize}
	% 	\item Деформация и течение потоков.
	% 	\item Искажение изображений через водную поверхность.
	% \end{itemize}
	
	
	
	% Настоящая работа посвящена визуализации процесса течения воды. В качестве основы для создания визуализации был использован фрагмент видеозаписи течения воды из крана, что дает возможность сравнить результаты цифровой визуализации с поведением жидкости в естественных условиях.
	
	% \vspace{5pt}
	
	% Ключевые аспекты реализации:
	
	% \begin{itemize}
	% 	\item \textbf{Динамика во времени}\\
	% 	Течение жидкости — это непрерывный процесс, в котором форма и объем потока постоянно меняются. Для достижения реалистичности требуется последовательная и поэтапная обработка генерации на различных участках струи.
		
	% 	\item\textbf{ Упрощенный подход к визуализации}\\
	% 	Несмотря на то, что в действительности движение жидкостей регулируется сложными законами гидродинамики, в данной работе основное внимание уделяется внешней, визуальной стороне процесса. Такой подход позволяет добиться высокой степени достоверности изображения без необходимости выполнения сложных вычислений.
		
	% \end{itemize}
	% Основная цель работы — создание реалистичной анимации процесса течения воды из крана, демонстрирующей ключевые физические свойства вещества при минимальных упрощениях.
	
	
	\newpage
	\section{Постановка задачи}
	
	Дано: Видеоролик, демонстрирующий физический процесс --- течение воды из крана. На записи также видно формирование и падение нескольких капель с головки крана. Один из кадров данного процесса показан на рисунке \hyperref[pic1]{1}.\par
	
	Цель работы: программными средствами визуализировать наблюдаемый на видеозаписи процесс.
	
	\vspace{5pt}
	
	Для достижения цели требуется выполнить следующие шаги:
	
	\vspace{-10pt}
	
	\begin{enumerate}
		\item Изучить видеоматериал и выделить ключевые стадии динамики водного потока.
		\item Разработать алгоритмы и подходы для визуальной реконструкции процесса.
		\item Реализовать визуализацию с применением графических библиотек, обеспечив:
		\begin{enumerate}
			\item естественное отображение колебаний и искажений водной струи;
			\item достоверную анимацию падения отдельных капель с учётом их прозрачности и размеров;
			\item возможность параметрической настройки характеристик струи (амплитуда колебаний, скорость появления капель).
		\end{enumerate}
	\end{enumerate}
	
	\begin{figure}[h]
	\centering{
		\includegraphics[width=80mm]{pic1.png}
		\caption{\centering{{Кадр видеофрагмента реального процесса}}}
	}
	\label{pic1}
\end{figure}\par
	

	
	
	
	\newpage
	\section{Описание физического процесса}
	
	Видео иллюстрирует физический процесс: течение воды из крана, который нобходимо было воспроизвести средствами процедурной анимации. Видео имеет разрешение $1600 \times 913$ пикселей, этого достаточно, чтобы заметить даже небольшие детали процесса, которые необходимо учесть при визуализации:
	
	\begin{itemize}
		\item \textbf{Динамика струи воды:}
		\begin{itemize}
			\item В начальный момент из крана выходит непрерывный поток воды, формирующий вытянутую струю.
			\item Струя не является идеально ровной --- под действием колебаний и турбулентности она искажается, создавая небольшую рябь на границах струи.
			\item Наблюдается постепенное движение воды влево и вправо, всего наблюдается 4 наиболее заметных и несколько небольших колебаний.
		\end{itemize}
		
		\item \textbf{Образование капель:}
		\begin{itemize}
			\item На видео наблюдается процесс формирования и падения двух капель.
			\item Капли имеют разный размер и форму, а также формируются в разных местах и с разной скоростью на головке крана.
			\item После формирования капли очень быстро падают вниз. Падение капель видно лишь на нескольких кадрах из-за небольшой частоты кадров видеозаписи.
		\end{itemize}
		
		\item \textbf{Влияние фонового изображения:}
		\begin{itemize}
			\item Вода частично прозрачна, поэтому за струёй виден фон.
			\item Фоновые объекты, видимые через струю, сильно искажаются из-за преломления света в воде.
		\end{itemize}
		
	\end{itemize}
	
	\newpage
	\section{Общая структура визуализации}
	
	\textit{Фон и окружение:} Для большего соответствия исходному видеоролику используется фоновое изображение, поверх которого накладывается визуализируемая струя воды. Это позволяет интегрировать анимацию в контекст сцены и повысить реализм изображения.
	
	\textit{Струя воды:} Основной элемент визуализации --- поток воды из крана, основные положения которой формируются по контурам, заданным масками. Для каждого шага анимации контуры интерполируются, что обеспечивает плавное изменение формы струи во времени.
	
	\textit{Дополнительные эффекты:} Во время течения воды, появляются капли, которые отрываются от верхней границы струи и движутся вниз, усиливая динамику сцены.
	
	\subsection{Подход к формированию струи}
	
	Визуализация строится на {геометрических контурах}, которые задаются масками. Каждая маска определяет форму и положения струи в пространстве в определенный момент времени. Плавность перехода между масками обеспечивается интерполяцией контуров.
	
	На форму добавляются синусоидальные колебания и случайные шумовые сдвиги, что позволяет создать характерную «живую» динамику воды.
	
	Для придания глубины и текстуры поток заливается цветным градиентом, плавно переходящим от более тёмных тонов к светлым.
	
	\subsubsection{Маски формы струи}
	Каждая маска задаёт положение струи на определённой фазе. Пример такой маски приведен на \hyperref[pic2]{рисунке 2} и \hyperref[pic3]{рисунке 3}. Последовательность масок определяет динамику движения струи влево и вправо.
	
	\begin{figure}[h!]
	\begin{multicols}{2}
		\hfill
				\includegraphics[width=100mm]{pic2.png}
		\caption{\centering{Начальная маска положения струи}} 
		\label{pic2}
		\hfill
					\includegraphics[width=100mm]{pic3.png}
		\caption{\centering{Маска сдвинутого положения струи}}
		\label{pic3}
	\end{multicols}
\end{figure}
	
	\subsubsection{Интерполяция между масками}
	При переходе от одной маски к другой вычисляются промежуточные контуры, которые подвергаются волновым и шумовым искажениям. Это позволяет струе двигаться и «колыхаться», имитируя естественное течение воды.
	
	\subsection{Динамические эффекты}
	
	\textbf{Искажения:} Для отрисовки бликов и неоднородной структуры потока под саму струю была подложена картинка бликов, изображенная на \hyperref[pic4]{рисунке 4}. Для получения эффекта размытия на подложку струи накладывается горизонтальное синусоидальное смещение строк изображения, что создаёт эффект размытости и движения.
	
	\textbf{Градиентная заливка:} Поток закрашивается набором полигонов с плавным изменением цвета и прозрачности, формируя характерное изменение цвета и прозрачности воды по времени ее стекания из крана.
	
	\textbf{Формирование капель:} На верхнем крае струи периодически появляются капли. Капли визуализируются как вытянутые эллипсы с частичной прозрачностью.
		
	\begin{figure}[h]
		\centering{
			\includegraphics[width=100mm]{pic4.png}
			\caption{\centering{{Подложка под струю, имитирующая блики и отражения окружающей среды}}}
		}
		\label{pic4}
	\end{figure}\par
		
	% \begin{figure}[h]
	% 	\centering{
	% 		\includegraphics[width=80mm]{pic5.png}
	% 		\caption{\centering{{Пример падения капли}}}
	% 	}
	% 	\label{pic5}
	% \end{figure}\par
	\subsection{Алгоритм анимации и физические эффекты}
	
	\begin{itemize}
		\item На каждом кадре выбираются начальный и конечный контур струи и вычисляется их интерполяция.
		\item К координатам контуров добавляются синусоидальные колебания и случайный шум.
		\item По получённым точкам строится маска, которая ограничивает область видимости подложки.
		\item Внутренняя область струи окрашивается с использованием цветового градиента.
		\item На верхнем крае струи (где она вытекает из под крана) периодически формируются капли. После форимрования капли падают вниз и скрываются за границей экрана.
	\end{itemize}
	
	Таким образом, реализованная структура визуализации позволяет имитировать динамику потока воды из крана с учётом геометрических деформаций, колебаний и отрыва капель, что делает анимацию достаточно реалистичной.
	
	\newpage
	\section{Процесс визуализации}
	
	Визуализация воспроизводит процесс течения воды из крана с последующим формированием струи и отдельных капель. Здесь применён геометрический подход: поток описывается через набор контуров, получаемых из масок и подвергаемых интерполяции и искажениям. Такая схема позволяет имитировать естественные колебания, разрывы и изменения формы водного потока.
	
	\subsection{Последовательность процесса визуализации}
	
	\subsubsection{Формирование и динамика струи}
	\begin{itemize}
		\item \textbf{Начальное появление:} 
		Струя формируется на основе исходной маски (\hyperref[pic2]{рисунок 2}), которая задаёт начальную геометрию потока.
		\item \textbf{Изменение формы:} 
		При переходе между масками используется интерполяция контуров. Дополнительно применяются синусоидальные колебания и шумовые искажения, что создаёт эффект подвижной струи с характерными колебаниями и неровностями.
		\item \textbf{Генерация капель:} 
		На верхнем крае потока периодически появляются отдельные капли, которые движутся вниз под действием гравитации. Их размер и прозрачность варьируются, что делает анимацию более естественной.
	\end{itemize}
	
	\subsubsection{Визуальные эффекты}
	\begin{itemize}
		\item \textbf{Прозрачность и цвет:} 
		Поток и капли визуализируются как полупрозрачные объекты с градиентной заливкой, что позволяет передать глубину, световые переходы и эффект преломления.
		\item \textbf{Фоновое изображение:} 
		На задний план накладывается статическое фото, что усиливает реалистичность сцены и создаёт контекст окружающей среды.
		\item \textbf{Искажения:} 
		Кадры подвергаются горизонтальному синусоидальному смещению, которое усиливает впечатление движения и дрожания струи.
	\end{itemize}
	
	\subsubsection{Завершение анимации}
	\begin{itemize}
		\item \textbf{Окончание симуляции:} 
		Визуализация продолжается до достижения последней маски либо заданного числа кадров. Каждый кадр сохраняется для последующего формирования видеоряда.
	\end{itemize}

\subsection{Используемые технологии и библиотеки}
Python --- основной язык программирования.

\subsubsection{Используемые библиотеки}
\begin{itemize}
	\item \textbf{Pygame} --- для создания окна, загрузки изображений, построения анимации и работы с масками.
	\begin{itemize}
		\item \texttt{pygame.init()} --- инициализирует все основные модули Pygame.
		\item \texttt{pygame.display.set\_mode()} --- создаёт окно приложения и поверхность для отрисовки.
		\item \texttt{pygame.image.load()} --- загружает изображения фона и масок.
		\item \texttt{pygame.Surface()} --- создаёт поверхности с поддержкой прозрачности, используемые для наложения эффектов.
		\item \texttt{pygame.draw.polygon()} и \texttt{pygame.draw.ellipse()} --- для отрисовки контура струи и капель воды.
		\item \texttt{pygame.display.flip()} --- обновляет окно, показывая отрисованный кадр.
		\item \texttt{pygame.time.Clock()} --- управляет частотой кадров анимации.
		\item \texttt{pygame.event.get()} --- отслеживает события (например, закрытие окна).
		\item \texttt{pygame.quit()} --- завершает работу программы и освобождает ресурсы.
	\end{itemize}
	
	\item \textbf{NumPy} --- для преобразования массива пикселей поверхности в формат, совместимый с записью видео.
	
	\item \textbf{Imageio} --- для записи последовательности кадров анимации в файл \texttt{.mp4}.
	
	\item \textbf{math} --- для вычисления синусоидальных искажений струи.
	
	\item \textbf{random} --- для внесения случайных колебаний в контуры и траектории капель.
\end{itemize}

\subsection{Основные числовые параметры}

\begin{itemize}
	\item \textit{Размер окна:} определяется автоматически по загруженному изображению фона (например, $400 \times 600$ пикселей).
	
	\item \textit{Частота кадров:} \texttt{FPS = 60} --- обеспечивает плавность анимации.
	
	\item \textit{Цвета струи:}
	\begin{itemize}
		\item Начальный цвет: \texttt{(55, 50, 45, 100)} --- тёмно-серый полупрозрачный.
		\item Конечный цвет: \texttt{(180, 180, 180, 50)} --- светло-серый с большей прозрачностью.
	\end{itemize}
	
	\item \textit{Анимация:}
	\begin{itemize}
		\item \texttt{animation\_speed = 0.005} --- скорость перехода между фазами.
		\item \texttt{amplitude = 2} --- амплитуда волнового искажения контура.
		\item \texttt{frequency = 0.05} --- частота волны.
		\item \texttt{t += 9} --- параметр времени, задающий движение искажения.
	\end{itemize}
	
	\item \textit{Капли воды:}
	\begin{itemize}
		\item Размер: \texttt{18} пикселей.
		\item Скорость падения: \texttt{35} пикселей за кадр.
		\item Цвет: полупрозрачный бело-голубой \texttt{(60, 55, 55, 30)}.
		\item Частота появления: \texttt{drop\_frequency = 1}.
	\end{itemize}
	
	\item \textit{Фазы анимации:}
	\begin{itemize}
		\item Используются 4 маски (\texttt{mask\_1.png} ... \texttt{mask\_4.png}), определяющие форму струи на каждом этапе.
		\item Интерполяция контуров плавно изменяет форму между фазами.
		\item Переключение фаз происходит при завершении цикла интерполяции.
	\end{itemize}
\end{itemize}

\vspace{15pt}
Таким образом, разработанная программа выполняет визуализацию движения водной струи с использованием масок, градиентной заливки и реалистичных капель, обеспечивая плавную анимацию и экспорт результата в видеофайл.

	\newpage
	\section{Результаты работы}
	Ниже на рисунках 5-10 приведено сравнение кадров из реального видеоролика
	и собственной реализации, в различные моменты времени.
	\begin{figure}[h!]
		\begin{multicols}{2}
			\hfill
			\includegraphics[width=80mm]{pic6.png}
					\caption{\centering{Начальный момент оригинального видео}} 
		\label{pic6}
			\hfill
			\includegraphics[width=80mm]{pic7.png}
			\hfill
					\caption{\centering{Начальный момент реализации}}
		\label{pic7}
		\end{multicols}
	\end{figure}
	\begin{figure}[h!]
		\begin{multicols}{2}
			\hfill
			\includegraphics[width=80mm]{pic8.png}
					\caption{\centering{Серединный момент оригинального видео}} 
		\label{pic8}
			\hfill
			\includegraphics[width=80mm]{pic9.png}
			\hfill
					\caption{\centering{Серединный момент реализации}}
		\label{pic9}
		\end{multicols}
	\end{figure}
	\begin{figure}[h!]
		\begin{multicols}{2}
			\hfill
			\includegraphics[width=80mm]{pic10.png}
					\caption{\centering{Конечный момент оригинального видео}} 
		\label{pic10}
			\hfill
			\includegraphics[width=80mm]{pic11.png}
			\hfill
					\caption{\centering{Конечный момент реализации}}
		\label{pic11}
		\end{multicols}
	\end{figure}
	\newpage
\hfill
\newpage
\addcontentsline{toc}{section}{Заключение}
\section*{Заключение}
В ходе выполнения лабораторной работы был проведён анализ видеозаписи, отображающей физический процесс вытекания воды из крана и её дальнейшего движения. На основе изучения динамики струи были определены ключевые особенности: постепенное изменение формы потока, появление колебаний, формирование капель и влияние случайных искажений на контур.

Для воспроизведения наблюдаемого эффекта была реализована программная визуализация на языке Python. Визуализация основана на интерполяции масок, описывающих форму струи на различных этапах, а также на применении дополнительных эффектов, таких как волновое искажение, градиентная заливка и генерация падающих капель.

В технической части использованы следующие приёмы:
\begin{enumerate}
	\item Применение альфа-канала для создания эффекта прозрачности воды;
	\item Использование масок для задания формы струи и плавной смены фаз;
	\item Добавление случайных искажений, формирующих реалистичные колебания потока;
	\item Генерация отдельных капель, усиливающих правдоподобность анимации;
	\item Экспорт последовательности кадров в видеофайл с помощью библиотеки \texttt{imageio}.
\end{enumerate}

Разработанная визуализация позволяет достоверно отобразить процесс формирования и движения струи воды, включая её деформацию и каплеобразование. Программная реализация на базе библиотек \texttt{Pygame}, \texttt{NumPy}, \texttt{imageio}, \texttt{math} и \texttt{random} обеспечила гибкость настройки и высокую наглядность результата.

Созданная программа может быть использована как демонстрационный инструмент при изучении явлений гидродинамики, а также как основа для дальнейших экспериментов по визуализации жидкостей в компьютерной графике. Полный исходный код представлен в приложении~A.


	\newpage
	\newpage 
	\newpage 
	
	
	
	\lstset{ 
		backgroundcolor=\color{white},
		frame=single
	}
	\newpage
	\addcontentsline{toc}{section}{Приложение А. Код реализации программы}
	\addcontentsline{toc}{subsection}{А.1 waterflow\_visualization.py}
	\section*{Приложение А. Код реализации программы}
	\subsection*{А.1 waterflow\_visualization.py}
	\begin{lstlisting}[language=Python, caption={Визуализация течения воды из крана}]
import pygame
import math
import random
import imageio
import numpy as np

pygame.init()

# --- Класс для капель воды ---
class WaterDrop:
	def __init__(self, x, y):
		self.x = x
		self.y = y
		self.size = 18
		self.speed = 35

		# Прозрачный бело-голубой цвет (альфа 120)
		self.color = (60, 55, 55, 30)
		
		self.ellipse_width = self.size
		self.ellipse_height = self.size * 1.5
		
	def update(self):
		self.y += self.speed
		
	def draw(self, screen):
		drop_rect = pygame.Rect(
			self.x - self.ellipse_width / 2,
			self.y - self.ellipse_height / 2,
			self.ellipse_width,
			self.ellipse_height,
		)
		
		# Временная поверхность с альфой
		drop_surface = pygame.Surface(
		(self.ellipse_width, self.ellipse_height), pygame.SRCALPHA
		)
		
		# Рисуем каплю на этой поверхности
		pygame.draw.ellipse(drop_surface, self.color, (0, 0, self.ellipse_width, self.ellipse_height))
		
		# Накладываем на экран
		screen.blit(drop_surface, drop_rect.topleft)
		
	def is_offscreen(self, screen_height):
		return self.y > screen_height


# --- Настройка экрана и загрузка ресурсов ---
try:
	temp_background_image = pygame.image.load("waterflow_background.png")
	width, height = temp_background_image.get_size()
	use_background = True
except pygame.error as e:
	print(f"Error loading background image: {e}")
	width, height = 400, 600
	use_background = False

screen = pygame.display.set_mode((width, height))

if use_background:
	background_image = temp_background_image.convert()

clock = pygame.time.Clock()

masks = []
try:
	mask1_image = pygame.image.load("mask_1.png").convert_alpha()
	mask2_image = pygame.image.load("mask_2.png").convert_alpha()
	mask3_image = pygame.image.load("mask_3.png").convert_alpha()
	mask4_image = pygame.image.load("mask_4.png").convert_alpha()
	masks = [mask1_image, mask2_image, mask3_image, mask4_image]
except pygame.error as e:
	print(f"Error loading mask images: {e}")
	pygame.quit()
	exit()

# --- Вырезаем базовую подложку из отдельной картинки ---
if use_background:
	base_mask = pygame.image.load("moving_image_4.png").convert_alpha()
	stream_base = pygame.Surface((width, height), pygame.SRCALPHA)
	stream_base.blit(background_image, (0, 0))
	stream_base.blit(base_mask, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)


# --- ФУНКЦИИ ---
def distort_only_stream(base, mask, t):
	"""Размывает и искажает подложку по маске"""
	w, h = base.get_size()
	distorted = pygame.Surface((w, h), pygame.SRCALPHA)

	for y in range(0, h, 2):
		offset = int(5 * math.sin(0.05 * y + t * 0.1))  # сдвиг строки
		distorted.blit(base, (offset, y), (0, y, w, 2))

# применяем маску струи
	distorted.blit(mask, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
	return distorted


def get_stream_contours(mask_surface):
	left_contour = []
	right_contour = []
	rows_data = {}
	for y in range(mask_surface.get_height()):
		left_x = -1
		right_x = -1
		for x in range(mask_surface.get_width()):
			if mask_surface.get_at((x, y))[0] < 50:
				if left_x == -1:
					left_x = x
				right_x = x
		if left_x != -1:
			rows_data[y] = (left_x, right_x)
	for y in sorted(rows_data.keys()):
			left_x, right_x = rows_data[y]
			left_contour.append((left_x, y))
			right_contour.append((right_x, y))
		return left_contour, right_contour


def make_stream_mask(left, right, width, height):
	mask_surface = pygame.Surface((width, height), pygame.SRCALPHA)
	polygon_points = left + right[::-1]
	pygame.draw.polygon(mask_surface, (255, 255, 255, 255), polygon_points)
	return mask_surface


def interpolate_countours(
start_left_contour_, start_right_contour_, end_left_contour_, end_right_contour_
):
	interpolated_left = []
	interpolated_right = []
	min_len_left = min(len(start_left_contour_), len(end_left_contour_))
	min_len_right = min(len(start_right_contour_), len(end_right_contour_))

	for i in range(min_len_left):
		start_x, start_y = start_left_contour_[i]
		end_x, end_y = end_left_contour_[i]
		interp_x = start_x + (end_x - start_x) * animation_progress
		wave1 = amplitude * math.sin(frequency * start_y + t)
		wave2 = (amplitude / 2) * math.sin(2 * frequency * start_y + 1.5 * t)
		noise = random.uniform(-0.5, 0.5)
		x_offset = wave1 + wave2 + noise
		interpolated_left.append((interp_x + x_offset, start_y))

	for i in range(min_len_right):
		start_x, start_y = start_right_contour_[i]
		end_x, end_y = end_right_contour_[i]
		interp_x = start_x + (end_x - start_x) * animation_progress
		wave1 = amplitude * math.sin(frequency * start_y + t)
		wave2 = (amplitude / 2) * math.sin(2 * frequency * start_y + 1.5 * t)
		noise = random.uniform(-0.5, 0.5)
		x_offset = wave1 + wave2 + noise
		interpolated_right.append((interp_x + x_offset, start_y))

	return interpolated_left, interpolated_right


# --- Контуры масок ---
contours = []
for mask in masks:
	left, right = get_stream_contours(mask)
	contours.append([left, right])

# --- Параметры ---
start_color = (55, 50, 45, 100)
end_color = (180, 180, 180, 50)
animation_progress = 0
animation_speed = 0.005
amplitude = 2
frequency = 0.05
t = 0
reverse = False
phase = 1
drops = []
FPS = 60
drop_frequency = 1
drop_counter = 0

writer = imageio.get_writer("animation_with_blur.mp4", fps=FPS)

# --- Главный цикл ---
running = True
while running:
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			running = False

	# --- Отрисовка фона ---
	if use_background:
		screen.blit(background_image, (0, 0))
	else:
		screen.fill((255, 255, 255))

	# Интерполяция контура струи
	interpolated_left, interpolated_right = interpolate_countours(
		contours[0][1], contours[0][0], contours[phase][1], contours[phase][0]
	)
	stream_mask = make_stream_mask(interpolated_left, interpolated_right, width, height)

	# --- Размытая и искажённая подложка ---
	distorted_stream = distort_only_stream(stream_base, stream_mask, t)
	screen.blit(distorted_stream, (0, 0))

	# --- Цветная заливка для струи ---
	polygon_points = interpolated_left + interpolated_right[::-1]
	if interpolated_left and interpolated_right:
		stream_surface = pygame.Surface((width, height), pygame.SRCALPHA)
	num_points = len(interpolated_left)
	for i in range(num_points - 1):
		r = int(start_color[0] + (end_color[0] - start_color[0]) * (i / num_points) ** 0.6)
		g = int(start_color[1] + (end_color[1] - start_color[1]) * (i / num_points) ** 0.6)
		b = int(start_color[2] + (end_color[2] - start_color[2]) * (i / num_points) ** 0.6)
		a = int(start_color[3] + (end_color[3] - start_color[3]) * (i / num_points) ** 0.2)
		points = [
			interpolated_left[i],
			interpolated_left[i + 1],
			interpolated_right[i + 1],
			interpolated_right[i],
		]
		pygame.draw.polygon(stream_surface, (r, g, b, a), points)
	screen.blit(stream_surface, (0, 0))

	coef = 3 if phase == 0 or phase == 1 else 1.5
	# --- Анимация прогресса ---
	animation_progress += animation_speed if not reverse else animation_speed * coef
	if animation_progress >= 1.0 or animation_progress <= 0.0:
		animation_speed *= -1
		if animation_progress <= 0.0:
			phase = min(3, phase + 1)
			drop_counter +=1
			reverse = not reverse
	animation_progress = max(0.0, min(1.0, animation_progress))

	t += 9
	if drop_counter >= drop_frequency:
		last_point_y = min(p[1] for p in polygon_points) + 25
		bottom_points_x = [p[0] for p in polygon_points if p[1] == last_point_y]
	if bottom_points_x:
		spawn_x = sum(bottom_points_x) / len(bottom_points_x)
		drops.append(WaterDrop(spawn_x + random.randint(-5, 5), last_point_y))
	drop_counter = 0

	new_drops_list = []
	for drop in drops:
		drop.update()
		drop.draw(screen)
		if not drop.is_offscreen(height):
			new_drops_list.append(drop)
	drops = new_drops_list
	pygame.display.flip()

	# --- Запись кадра ---
	frame = pygame.surfarray.array3d(screen)
	frame = np.swapaxes(frame, 0, 1)
	writer.append_data(frame)

	clock.tick(FPS)

writer.close()
pygame.quit()

	\end{lstlisting}
\end{document}
