Twirl Filter 在圓形區域內產生角度隨半徑非線性旋轉的漩渦效果。中心旋轉角度最大,向邊緣遞減至零,形成螺旋狀幾何變形。
(centreX, centreY)、最大旋轉角度 angle、影響半徑 radius(0 表示自動取短邊一半)。(x, y),計算相對中心向量 (dx, dy) 及距離 distance = sqrt(dx²+dy²)。distance > radius,保持原位。a = atan2(dy, dx) + angle * (radius - distance) / radius。distance=0 旋轉 angle,邊緣 distance=radius 旋轉 0。new_x = cx + distance * cos(a),new_y = cy + distance * sin(a)。#include <opencv2/opencv.hpp>
#include <cmath>
#include <algorithm>
using namespace cv;
using namespace std;
void showImage(const Mat& img, const string& name) {
namedWindow(name, WINDOW_AUTOSIZE);
imshow(name, img);
}
int main() {
Mat src = imread("4.jpg");
if (src.empty()) return -1;
Mat dst(src.size(), src.type());
src.copyTo(dst); // 初始化為原圖,未變形區域保持原樣
int w = src.cols, h = src.rows;
float cx = w * 0.5f, cy = h * 0.5f;
float radius = 0.0f;
if (radius == 0) radius = min(w, h) * 0.5f;
float radius2 = radius * radius;
float angle = CV_PI / 3; // 60 度最大旋轉
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
float dx = x - cx, dy = y - cy;
float dist2 = dx*dx + dy*dy;
float nx = x, ny = y;
if (dist2 < radius2 && dist2 > 0) {
float distance = sqrt(dist2);
float a = atan2(dy, dx) + angle * (radius - distance) / radius;
nx = cx + distance * cos(a);
ny = cy + distance * sin(a);
}
// 邊界裁剪
nx = max(0.0f, min(nx, w - 2.0f));
ny = max(0.0f, min(ny, h - 2.0f));
int x1 = (int)nx, y1 = (int)ny;
float px = nx - x1, py = ny - y1;
for (int k = 0; k < 3; ++k) {
dst.at<Vec3b>(y, x)[k] = saturate_cast<uchar>(
(1-px)*(1-py)*src.at<Vec3b>(y1, x1)[k] +
px*(1-py)*src.at<Vec3b>(y1, x1+1)[k] +
(1-px)*py*src.at<Vec3b>(y1+1, x1)[k] +
px*py*src.at<Vec3b>(y1+1, x1+1)[k]
);
}
}
}
showImage(dst, "Twirl Effect");
waitKey(0);
return 0;
}
angle:正值順時針漩渦,負值逆時針。典型 π/4 ~ π。radius:控制影響範圍。較小值產生局部漩渦,較大值影響全圖。(radius - distance)^2 / radius^2 產生更銳利漩渦核心。