diff --git a/.gitignore b/.gitignore index a59852a..9c37c06 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ RTX2090TiFy # Exports *.avi *.mp4 + +# Temp +temp diff --git a/CMakeLists.txt b/CMakeLists.txt index b9d86e5..5afa17b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.16) -project(RTX-2090-TiFy VERSION 1.0.9) +project(RTX-2090-TiFy VERSION 1.0.38) set(APP_VERSION "${CMAKE_PROJECT_VERSION}") configure_file(config/AppProps.h.in ${CMAKE_CURRENT_BINARY_DIR}/gen/AppProps.h) diff --git a/inc/ImageUtils.hpp b/inc/CorgiAlgorithm.hpp similarity index 100% rename from inc/ImageUtils.hpp rename to inc/CorgiAlgorithm.hpp diff --git a/inc/RTX2090Ti.hpp b/inc/RTX2090Ti.hpp index d7d5938..f459a21 100644 --- a/inc/RTX2090Ti.hpp +++ b/inc/RTX2090Ti.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include "Configurations.hpp" @@ -25,7 +27,12 @@ class RTX2090Ti bool buildVideo(); private: - void RayTracing(cv::Mat &canvas, std::pair &Start, std::pair &End); + // * For each Frames + void RayTracing(cv::VideoWriter &OutVideo, std::pair &Start, std::pair &End, + std::pair &OriginalLoc); + void renderPixel(int c, int r, std::pair &Start, std::pair &End, + cv::Mat &normalizedPic, cv::Mat &RenderOn, std::pair &OriginalLoc); + void safeCopyTo(cv::Mat&src, cv::Mat &dest, cv::Rect& roi); void linkAudio(); std::string statusMessage(int loopsDone, int allLoops, int framesDone, int allFrames); }; diff --git a/src/ImageUtils.cpp b/src/CorgiAlgorithm.cpp similarity index 93% rename from src/ImageUtils.cpp rename to src/CorgiAlgorithm.cpp index 2cb650e..d9150eb 100644 --- a/src/ImageUtils.cpp +++ b/src/CorgiAlgorithm.cpp @@ -1,6 +1,5 @@ -#include "ImageUtils.hpp" +#include "CorgiAlgorithm.hpp" -#include #include #include #include diff --git a/src/RTX2090Ti.cpp b/src/RTX2090Ti.cpp index f2cb879..080ebd2 100644 --- a/src/RTX2090Ti.cpp +++ b/src/RTX2090Ti.cpp @@ -3,12 +3,15 @@ #include #include #include +#include #include +#include +#include #include #include #include "Configurations.hpp" -#include "ImageUtils.hpp" +#include "CorgiAlgorithm.hpp" RTX2090Ti::RTX2090Ti(wxWindow *parent, cv::Mat BaseImage, Configurations &Config) : parent(parent), Config(Config), fourcc(cv::VideoWriter::fourcc(MYCODEC)) @@ -18,19 +21,17 @@ RTX2090Ti::RTX2090Ti(wxWindow *parent, cv::Mat BaseImage, Configurations &Config rows = y; cv::resize(BaseImage, this->BaseImage, cv::Size(x, y)); - cv::cvtColor(BaseImage, BaseImageGray, cv::COLOR_BGR2GRAY); + cv::cvtColor(this->BaseImage, BaseImageGray, cv::COLOR_BGR2GRAY); OutVideo = cv::VideoWriter(Config.OutVideoPath + ".avi", fourcc, Config.FPS, cv::Size(cols, rows)); + OutVideo.write(this->BaseImage); } bool RTX2090Ti::buildVideo() { auto start{std::clock()}; - const int bigcols = cols * cols; - const int bigrows = rows * rows; - int totalFrames = Config.FPS * Config.LoopDuration; wxProgressDialog BuildProgress("Building Video...", @@ -60,18 +61,18 @@ bool RTX2090Ti::buildVideo() int right = cols * (cols - point.first - 1); int down = rows * (rows - point.second - 1); - for (int f = 0; f < totalFrames; f++) + for (int f = 1; f <= totalFrames; f++) { - double expansionRate = f / totalFrames; + double expansionRate = (double)f / totalFrames; + expansionRate = std::pow(expansionRate, 2.5); + std::pair LocalStart{Start.first - left * expansionRate, Start.second - up * expansionRate}; std::pair LocalEnd{End.first + right * expansionRate, End.second + down * expansionRate}; - RayTracing(temp, LocalStart, LocalEnd); + RayTracing(OutVideo, LocalStart, LocalEnd, point); - OutVideo.write(temp); - cv::imshow("Live Preview", temp); BuildProgress.Update(framesDone + f, statusMessage(loopDone, Config.nLoops, f, totalFrames)); } @@ -81,9 +82,10 @@ bool RTX2090Ti::buildVideo() cv::destroyAllWindows(); OutVideo.release(); - std::cout << "Video Build Success (ทิพย์)\n"; + std::cout << "Video Build Success\n"; BuildProgress.Update(totalFrames * Config.nLoops, "Linking Audio..."); + linkAudio(); auto end{std::clock()}; @@ -105,14 +107,143 @@ bool RTX2090Ti::buildVideo() return true; } -void RTX2090Ti::RayTracing(cv::Mat &canvas, std::pair &Start, std::pair &End) +void RTX2090Ti::RayTracing(cv::VideoWriter &OutVideo, std::pair &Start, + std::pair &End, std::pair &OriginalLoc) { + if ((End.first - Start.first) / cols > 0.2 * cols) + { + cv::Mat cropped_img = BaseImage(cv::Range(Start.second / rows, End.second / rows), + cv::Range(Start.first / cols, End.first / cols)); + + cv::resize(cropped_img, cropped_img, cv::Size(cols, rows)); + OutVideo.write(cropped_img); + + cv::imshow("Live Preview", cropped_img); + return; + } + + cv::Mat Canvas = cv::Mat::zeros(cv::Size(cols, rows), CV_8UC3); + + std::pair Imsize{End.first - Start.first, End.second - Start.second}; std::pair BigTileStart{Start.first / cols, Start.second / rows}; std::pair BigTileEnd{std::ceil((double)End.first / cols), std::ceil((double)End.second / rows)}; - canvas = Corgi::changeTone(BaseImageGray, std::tuple(0, 0, 255)); + std::pair PixelSize{cols * cols / Imsize.first + 1, rows * rows / Imsize.second + 1}; + + cv::Mat SmolImage; + cv::resize(BaseImageGray, SmolImage, cv::Size(PixelSize.first, PixelSize.second)); + + for (int c = BigTileStart.first; c < BigTileEnd.first; c++) + { + for (int r = BigTileStart.second; r < BigTileEnd.second; r++) + { + renderPixel(c, r, Start, End, SmolImage, Canvas, OriginalLoc); + } + } + + OutVideo.write(Canvas); + cv::imshow("Live Preview", Canvas); +} + +void RTX2090Ti::renderPixel(int c, int r, std::pair &Start, std::pair &End, + cv::Mat &normalizedPic, cv::Mat &RenderOn, + std::pair &OriginalLoc) +{ + cv::Vec3b color = BaseImage.at(cv::Point(c, r)); + cv::Mat ColoredImg = + Corgi::changeTone(normalizedPic, std::tuple(color[0], color[1], color[2])); + + cv::Point renderOnPos((c * cols - Start.first) * cols / (End.first - Start.first), + (r * rows - Start.second) * rows / (End.second - Start.second)); + + cv::Point renderEnd(renderOnPos.x + normalizedPic.cols, renderOnPos.y + normalizedPic.rows); + + cv::Rect renderRange(renderOnPos, renderEnd); + + assert(normalizedPic.cols <= cols); + assert(normalizedPic.rows <= rows); + + // * Case: Original Picture + if (c == OriginalLoc.first && r == OriginalLoc.second) + { + cv::Mat toRender; + cv::resize(BaseImage, toRender, cv::Size(normalizedPic.cols, normalizedPic.rows)); + + try + { + toRender.copyTo(RenderOn(renderRange)); + } + catch (...) + { + std::cout << renderOnPos << " " << renderEnd << "\n"; + } + return; + } + + // * General Case + + safeCopyTo(ColoredImg, RenderOn, renderRange); +} + +void RTX2090Ti::safeCopyTo(cv::Mat &src, cv::Mat &dest, cv::Rect &roi) +{ + std::pair newXRange{0, roi.width}; + std::pair newYRange{0, roi.height}; + + bool left{false}; + bool up{false}; + bool right{false}; + bool down{false}; + + if (roi.x < 0) + { + newXRange.first = -roi.x; + left = true; + } + if (roi.y < 0) + { + newYRange.first = -roi.y; + up = true; + } + if (roi.x + roi.width > cols) + { + newXRange.second = cols - roi.x; + right = true; + } + if (roi.y + roi.height > rows) + { + newYRange.second = rows - roi.y; + down = true; + } + + if (left || up || right || down) + { + src = src(cv::Range(newYRange.first, newYRange.second), + cv::Range(newXRange.first, newXRange.second)); + + if (left) + { + roi.width += roi.x; + roi.x = 0; + } + if (right) + { + roi.width = src.cols; + } + if (up) + { + roi.height += roi.y; + roi.y = 0; + } + if (down) + { + roi.height = src.rows; + } + } + + src.copyTo(dest(roi)); } void RTX2090Ti::linkAudio()