在計算機視覺和圖像處理領域,OpenCV 提供了非常強大的圖像幾何變換能力,不僅可以用于糾正圖像,還能制造各種“有趣”的視覺效果。今天,我們就來實現一個經典的“哈哈鏡”效果,讓圖像像在游樂園里一樣被拉伸、壓縮、扭曲,創造出令人發笑的面部或形體變形。
🎯 什么是“哈哈鏡”?
“哈哈鏡”是一種非線性扭曲鏡面,會在不同區域產生放大或縮小的視覺錯覺。我們可以用數學變換模擬出類似的效果,比如:
-
水平凹面/凸面:圖像左右邊緣被拉伸或收縮
-
垂直凹面/凸面:圖像上下邊緣被拉伸或壓縮
-
中心凹面/凸面:圖像向內或向外膨脹
-
水波擾動:從若干中心點向外擴散波紋,模擬水面晃動感
🔧 技術實現原理
我們將使用 OpenCV 的 remap
函數,它允許我們通過兩個映射矩陣 map_x
和 map_y
,定義每個輸出像素應該對應輸入圖像的哪個位置。
關鍵在于如何構造這兩個映射矩陣,讓它們產生扭曲效果。
🧪 示例代碼:中心凸面效果(魚眼)
import cv2
import numpy as npdef funhouse_effect(frame):h, w = frame.shape[:2]map_y, map_x = np.indices((h, w), dtype=np.float32)# 計算圖像中心cx, cy = w // 2, h // 2# 構造相對坐標dx = map_x - cxdy = map_y - cyr = np.sqrt(dx**2 + dy**2)r_max = np.max(r)# 控制扭曲強度k = 0.0008 # 越大越扭曲(中心凸出)scale = 1 + k * (r**2) # 非線性放大map_x = cx + dx * scalemap_y = cy + dy * scale# 保證映射范圍合法map_x = np.clip(map_x, 0, w - 1)map_y = np.clip(map_y, 0, h - 1)return cv2.remap(frame, map_x, map_y, interpolation=cv2.INTER_LINEAR)frame = cv2.imread("face.jpg")
output = funhouse_effect(frame)
cv2.imwrite("distorted.jpg", output)
📚 多種哈哈鏡效果
你可以基于上面的思路實現更多效果:
效果類型 | 扭曲方式示意 | 說明 |
---|---|---|
水平凹面 | scale = 1 - k * ((x-cx)/cx)^2 | 中心寬、邊窄 |
垂直凸面 | scale = 1 + k * ((y-cy)/cy)^2 | 中心鼓起 |
中心凹面 | scale = 1 - k * r^2 | 邊緣大、中心小 |
隨機水波擾動 | sin(r * 頻率 + 相位) 疊加擾動 | 水波紋起伏感 |
🔄 通用框架:FrameObject 封裝
為了在實時視頻或處理多個幀時使用,我們可以封裝為如下類:
class FrameObject:def __init__(self):self.mode = 'random_wave' # 選擇效果def do(self, frame, device):h, w = frame.shape[:2]map_y, map_x = np.indices((h, w), dtype=np.float32)cx, cy = w // 2, h // 2dx = map_x - cxdy = map_y - cyr = np.sqrt(dx**2 + dy**2)if self.mode == 'center_fisheye':scale = 1 + 0.0006 * (r**2)map_x = cx + dx * scalemap_y = cy + dy * scaleelif self.mode == 'horizontal_cave':scale = 1 - 0.0012 * ((dx / cx) ** 2)map_x = cx + dx * scalemap_y = map_yelif self.mode == 'random_wave':for _ in range(np.random.randint(1, 4)):wave_cx = np.random.randint(w // 4, 3 * w // 4)wave_cy = np.random.randint(h // 4, 3 * h // 4)ddx = map_x - wave_cxddy = map_y - wave_cyrr = np.sqrt(ddx**2 + ddy**2)phase = np.random.uniform(0, 2 * np.pi)displacement = 8 * np.sin(rr * 0.05 + phase)map_x += displacement * (ddx / (rr + 1e-6))map_y += displacement * (ddy / (rr + 1e-6))map_x = np.clip(map_x, 0, w - 1)map_y = np.clip(map_y, 0, h - 1)return cv2.remap(frame, map_x, map_y, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT)
🎥 應用場景
-
互動鏡像設備(如景區搞笑自拍)
-
視頻濾鏡制作(社交媒體)
-
教學演示圖像幾何變換原理
-
圖像增強(用作數據增強的一種方式)
🧠 總結
使用 OpenCV,我們可以輕松實現各種非線性圖像變換來模擬“哈哈鏡”效果。本質上是通過構建合適的映射矩陣 map_x
和 map_y
,來控制每個像素的位置變換。配合正弦波、極坐標縮放、指數函數等,你可以無限創造各種扭曲方式。
如果你對某種特定變形方式感興趣,或者想將其用于實時視頻流、交互系統中,歡迎留言交流!🎉