Skip to content

Instantly share code, notes, and snippets.

@zr0n
Last active April 15, 2025 17:50
Show Gist options
  • Save zr0n/9d8c1197943ba56ff8ed9a843fcb45ab to your computer and use it in GitHub Desktop.
Save zr0n/9d8c1197943ba56ff8ed9a843fcb45ab to your computer and use it in GitHub Desktop.
#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;
}
@zr0n
Copy link
Author

zr0n commented Apr 6, 2025

#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

@zr0n
Copy link
Author

zr0n commented Apr 11, 2025

Compile and Run

g++ -O3 magic_mirror.cpp -o mirror $(pkg-config --cflags --libs opencv4) -lX11
./mirror

@zr0n
Copy link
Author

zr0n commented Apr 11, 2025

Better compiling options (more performance)

g++ -O3 -march=native -ffast-math -fopenmp magic_mirror.cpp -o mirror $(pkg-config --cflags --libs opencv4) -lX11

@zr0n
Copy link
Author

zr0n commented Apr 11, 2025

Melhor desempenho (Raspberry pi 3)

sudo systemctl stop bluetooth.service
sudo systemctl stop avahi-daemon.service
sudo nice -n -20 ./mirror

@eliasfeijo
Copy link

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