Last active
April 15, 2025 17:50
-
-
Save zr0n/9d8c1197943ba56ff8ed9a843fcb45ab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <opencv2/opencv.hpp> | |
#include <X11/Xlib.h> | |
using namespace cv; | |
using namespace std; | |
// ====================== | |
// Optimized Settings | |
// ====================== | |
#define PROCESS_WIDTH 320 | |
#define PROCESS_HEIGHT 240 | |
#define MAX_WARP 200.0f | |
#define MAX_DELAY_WEIGHT 0.95f | |
#define MAX_VORTEX_POWER 5.0f // Maximum vortex intensity | |
#define MAX_VORTEX_SPEED 2.0f // Maximum rotation speed | |
// Global controls | |
float g_warp_intensity = 40.0f; | |
float g_warp_speed = 0.5f; | |
float g_color_speed = 0.4f; | |
float g_delay_weight = 0.85f; | |
float g_vortex_power = 1.0f; // Vortex effect intensity | |
float g_vortex_speed = 0.5f; // Vortex rotation speed | |
// Effect buffers | |
Mat g_accumulated_frame; | |
// ====================== | |
// Vortex Effect Function | |
// ====================== | |
void apply_vortex_effect(Mat& frame, double time) { | |
Mat map_x(frame.size(), CV_32F); | |
Mat map_y(frame.size(), CV_32F); | |
const Point center(frame.cols/2, frame.rows/2); | |
const float max_radius = sqrt(center.x*center.x + center.y*center.y); | |
parallel_for_(Range(0, frame.rows), [&](const Range& range) { | |
for(int y = range.start; y < range.end; y++) { | |
float* mx = map_x.ptr<float>(y); | |
float* my = map_y.ptr<float>(y); | |
for(int x = 0; x < frame.cols; x++) { | |
// Convert to polar coordinates | |
float dx = x - center.x; | |
float dy = y - center.y; | |
float radius = sqrt(dx*dx + dy*dy); | |
float angle = atan2(dy, dx); | |
// Apply vortex transformation | |
float spiral = g_vortex_power * (radius/max_radius); | |
angle += spiral + time * g_vortex_speed; | |
// Convert back to cartesian | |
mx[x] = center.x + radius * cos(angle); | |
my[x] = center.y + radius * sin(angle); | |
} | |
} | |
}); | |
remap(frame, frame, map_x, map_y, INTER_LINEAR, BORDER_REFLECT); | |
} | |
// ====================== | |
// Delay Effect (Maintained) | |
// ====================== | |
void apply_delay_effect(Mat& current_frame) { | |
if(g_accumulated_frame.empty()) { | |
current_frame.copyTo(g_accumulated_frame); | |
return; | |
} | |
addWeighted(g_accumulated_frame, g_delay_weight, | |
current_frame, 1.0f - g_delay_weight, | |
0, g_accumulated_frame); | |
g_accumulated_frame.copyTo(current_frame); | |
} | |
// ====================== | |
// Warp Effect (Maintained) | |
// ====================== | |
void apply_warp_effect(Mat& frame, double time) { | |
Mat warped(frame.size(), frame.type()); | |
const float freq = 0.03f; | |
for(int y = 0; y < frame.rows; y++) { | |
for(int x = 0; x < frame.cols; x++) { | |
float dx = g_warp_intensity * sin(time * g_warp_speed + x * freq); | |
float dy = g_warp_intensity * cos(time * g_warp_speed * 0.8f + y * freq * 0.7f); | |
int src_x = cv::borderInterpolate(x + dx, frame.cols, BORDER_REFLECT); | |
int src_y = cv::borderInterpolate(y + dy, frame.rows, BORDER_REFLECT); | |
warped.at<Vec3b>(y,x) = frame.at<Vec3b>(src_y, src_x); | |
} | |
} | |
warped.copyTo(frame); | |
} | |
// ====================== | |
// Color Effect (Maintained) | |
// ====================== | |
void apply_color_effect(Mat& frame, double time) { | |
Mat hsv; | |
cvtColor(frame, hsv, COLOR_BGR2HSV); | |
for(int y = 0; y < hsv.rows; y++) { | |
for(int x = 0; x < hsv.cols; x++) { | |
hsv.at<Vec3b>(y,x)[0] = fmod(time * 20 * g_color_speed + (x+y) * 0.5, 180); | |
} | |
} | |
cvtColor(hsv, frame, COLOR_HSV2BGR); | |
} | |
// ====================== | |
// Main Processing Loop | |
// ====================== | |
int main() { | |
// Initialize display | |
int screen_w, screen_h; | |
Display* d = XOpenDisplay(nullptr); | |
screen_w = XDisplayWidth(d, 0); | |
screen_h = XDisplayHeight(d, 0); | |
XCloseDisplay(d); | |
// Camera setup | |
VideoCapture cap(0); | |
cap.set(CAP_PROP_FRAME_WIDTH, PROCESS_WIDTH); | |
cap.set(CAP_PROP_FRAME_HEIGHT, PROCESS_HEIGHT); | |
cap.set(CAP_PROP_BUFFERSIZE, 1); | |
// Window configuration | |
namedWindow("PsychoMirror", WINDOW_FULLSCREEN); | |
setWindowProperty("PsychoMirror", WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN); | |
Mat frame, output; | |
double start = (double)getTickCount()/getTickFrequency(); | |
while(true) { | |
double t = ((double)getTickCount()/getTickFrequency()) - start; | |
if(!cap.read(frame)) continue; | |
// Effect pipeline | |
flip(frame, frame, 1); | |
apply_vortex_effect(frame, t); // New vortex effect | |
apply_warp_effect(frame, t); | |
apply_color_effect(frame, t); | |
apply_delay_effect(frame); | |
// Upscale and display | |
resize(frame, output, Size(screen_w, screen_h), 0, 0, INTER_LINEAR); | |
imshow("PsychoMirror", output); | |
// Control handling | |
int key = waitKey(1); | |
if(key == 'q') break; | |
if(key == 'w') g_warp_intensity = min(g_warp_intensity+5, MAX_WARP); | |
if(key == 's') g_warp_intensity = max(g_warp_intensity-5, 0.0f); | |
if(key == 'e') g_delay_weight = min(g_delay_weight+0.05f, MAX_DELAY_WEIGHT); | |
if(key == 'd') g_delay_weight = max(g_delay_weight-0.05f, 0.0f); | |
if(key == 'v') g_vortex_power = min(g_vortex_power+0.1f, MAX_VORTEX_POWER); | |
if(key == 'b') g_vortex_power = max(g_vortex_power-0.1f, 0.0f); | |
if(key == 'n') g_vortex_speed = min(g_vortex_speed+0.1f, MAX_VORTEX_SPEED); | |
if(key == 'm') g_vortex_speed = max(g_vortex_speed-0.1f, 0.0f); | |
} | |
cap.release(); | |
destroyAllWindows(); | |
return 0; | |
} |
Compile and Run
g++ -O3 magic_mirror.cpp -o mirror $(pkg-config --cflags --libs opencv4) -lX11
./mirror
Better compiling options (more performance)
g++ -O3 -march=native -ffast-math -fopenmp magic_mirror.cpp -o mirror $(pkg-config --cflags --libs opencv4) -lX11
Melhor desempenho (Raspberry pi 3)
sudo systemctl stop bluetooth.service
sudo systemctl stop avahi-daemon.service
sudo nice -n -20 ./mirror
Adapted code for compiling and running on Windows / VS2022
(Basically the same as the original, I just removed the X11 dependency and used the OpenCV built-in window system instead)
// magic_mirror.cpp
#include <opencv2/opencv.hpp>
#include <iostream>
#include "wtypes.h"
using namespace cv;
using namespace std;
// ======================
// Configurações Otimizadas
// ======================
#define PROCESS_WIDTH 320 // Reduzido para melhor performance
#define PROCESS_HEIGHT 240
#define MAX_WARP 200.0f
#define SCALE_FACTOR 2 // Fator de upscale
// Controles Globais
float g_warp_intensity = 80.0f;
float g_warp_speed = 0.8f;
float g_color_speed = 0.4f;
// ======================
// Efeito de Distorção Original
// ======================
void apply_warp_effect(Mat& frame, double time) {
Mat warped(frame.size(), frame.type());
const float freq = 0.03f;
for (int y = 0; y < frame.rows; y++) {
for (int x = 0; x < frame.cols; x++) {
// Cálculo original do warp
float dx = g_warp_intensity *
sin(time * g_warp_speed + x * freq);
float dy = g_warp_intensity *
cos(time * g_warp_speed * 0.8f + y * freq * 0.7f);
int src_x = cv::borderInterpolate(x + dx, frame.cols, BORDER_REFLECT);
int src_y = cv::borderInterpolate(y + dy, frame.rows, BORDER_REFLECT);
warped.at<Vec3b>(y, x) = frame.at<Vec3b>(src_y, src_x);
}
}
warped.copyTo(frame);
}
// ======================
// Efeito de Cores Original
// ======================
void apply_color_effect(Mat& frame, double time) {
Mat hsv;
cvtColor(frame, hsv, COLOR_BGR2HSV);
// Padrão de cores original
for (int y = 0; y < hsv.rows; y++) {
for (int x = 0; x < hsv.cols; x++) {
hsv.at<Vec3b>(y, x)[0] = fmod(
time * 20 * g_color_speed + (x + y) * 0.5,
180
);
}
}
cvtColor(hsv, frame, COLOR_HSV2BGR);
}
// ======================
// Loop Principal Otimizado
// ======================
int main() {
// Configurar fullscreen corretamente
int screen_w, screen_h;
RECT desktop;
// Get a handle to the desktop window
const HWND hDesktop = GetDesktopWindow();
// Get the size of screen to the variable desktop
GetWindowRect(hDesktop, &desktop);
// The top left corner has coordinates (0,0)
screen_w = desktop.right;
screen_h = desktop.bottom;
// Inicializar captura de vídeo
VideoCapture cap(0);
cap.set(CAP_PROP_FRAME_WIDTH, PROCESS_WIDTH);
cap.set(CAP_PROP_FRAME_HEIGHT, PROCESS_HEIGHT);
cap.set(CAP_PROP_BUFFERSIZE, 1);
namedWindow("MirrorFX", WINDOW_NORMAL);
setWindowProperty("MirrorFX", WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
Mat frame, processed, output;
double start = (double)getTickCount() / getTickFrequency();
while (true) {
double t = ((double)getTickCount() / getTickFrequency()) - start;
if (!cap.read(frame)) continue;
// Pipeline original com otimizações
flip(frame, frame, 1);
apply_warp_effect(frame, t); // Efeito original
apply_color_effect(frame, t); // Efeito original
// Upscale rápido para fullscreen
resize(frame, output, Size(screen_w, screen_h), 0, 0, INTER_LINEAR);
imshow("MirrorFX", output);
// Controles
int key = waitKey(1);
if (key == 'q' || key == 27) break; // 'q' ou ESC para sair
if (key == 'w') g_warp_intensity = min(g_warp_intensity + 5, MAX_WARP);
if (key == 's') g_warp_intensity = max(g_warp_intensity - 5, 0.0f);
}
cap.release();
destroyAllWindows();
return 0;
}
Dependencies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
#Dependency
Atualiza a lista de pacotes
sudo apt update
Instala as dependências ESSENCIAIS (C++ + OpenCV)
sudo apt install -y build-essential cmake libopencv-dev libopencv-core-dev libopencv-highgui-dev libopencv-imgproc-dev libopencv-video-dev libopencv-objdetect-dev