首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

OpenCV 影像特效:Pinch Filter(捏合扭曲效果)實現

     編輯:關於C++

效果描述

Pinch Filter 產生向內/向外捏合的幾何變形,類似透過凸/凹透鏡觀看影像。中心區域被壓縮或拉伸,邊緣區域相對變形較小。

核心演算法

  1. 設定效果中心 (centreX, centreY)(歸一化 0~1)、半徑 radius、扭曲強度 amount、旋轉角度 angle。
  2. 對每個輸出像素 (x, y),計算相對中心向量 (dx, dy) 及距離平方 distance2。
  3. 若超出半徑或距離為 0,保持原位:new_x=x, new_y=y。
  4. 否則計算歸一化距離 d = sqrt(distance2) / radius。
  5. 徑向縮放:t = pow(sin(π/2 * d), -amount)。amount > 0 向內捏合,amount < 0 向外膨脹。更新 dx *= t, dy *= t。
  6. 角度旋轉:a = angle * (1-d)^2,距離中心越遠旋轉越小。套用旋轉矩陣:new_x = cx + cos(a)*dx - sin(a)*dy,new_y = cy + sin(a)*dx + cos(a)*dy。
  7. 雙線性插值採樣原圖對應位置像素值寫入輸出。

關鍵參數

  • radius=0 時自動設為 min(width, height)/2。
  • amount=0.5 為中等捏合強度。
  • 邊界檢查:採樣座標限制在 [0, width-2] × [0, height-2] 確保雙線性插值不越界。

完整 OpenCV C++ 實現

#include <opencv2/opencv.hpp>
#include <cmath>
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());

    int w = src.cols, h = src.rows;
    float cx = w * 0.5f, cy = h * 0.5f;
    float radius = 200.0f;
    if (radius == 0) radius = min(w, h) * 0.5f;
    float radius2 = radius * radius;
    float amount = 0.5f;
    float angle = CV_PI / 2;

    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 d = sqrt(dist2) / radius;
                float t = pow(sin(CV_PI * 0.5f * d), -amount);
                dx *= t; dy *= t;
                float e = 1.0f - d;
                float a = angle * e * e;
                float s = sin(a), c = cos(a);
                nx = cx + c*dx - s*dy;
                ny = cy + s*dx + c*dy;
            }
            // 邊界裁剪
            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, "Pinch Effect");
    waitKey(0);
    return 0;
}

效果展示

Pinch Filter 效果圖

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved