import cv2 import imageio.v2 as iio from PIL import Image import copy import operator import math import numpy as np class LocalWarpEffect(object): '''Interactive Image Warping Effect:互動式扭曲影像效果(可以理解為平滑的拉伸\扭曲影像) @note 參考文獻: Interactive Image Warping by Andreas Gustafsson 說明:該演算法利用區域性的平移、縮放以及旋轉的方式來不失真的進行影像纖瘦化處理。 ''' def __init__(self, center, mouse, radius, antialias=2): ''' @param center 區域性變形效果的圓心,可以認為是滑鼠按下起點 @param mouse 滑鼠釋放的位置 ''' self.center = center self.mouse = mouse self.radius = radius self.antialias = antialias def warp(self, x, y, r, center, mouse): cx, cy = center mx, my = mouse dis_x_c = math.sqrt((x - cx) ** 2 + (y - cy) ** 2) dis_m_c = math.sqrt((x - mx) ** 2 + (y - my) ** 2) div = float(r ** 2 - dis_x_c ** 2 + dis_m_c ** 2) if div == 0: div = 0.0000000001 factor = ((r ** 2 - dis_x_c ** 2) / div) ** 2 u = x - factor * (mx - cx) v = y - factor * (my - cy) return u, v def __call__(self, img): width, height = img.size new_img = img.copy() r = self.radius cx, cy = self.center mx, my = self.mouse nband = len(img.getpixel((0, 0))) antialias = self.antialias for x in range(width): for y in range(height): if math.sqrt((x - cx) ** 2 + (y - cy) ** 2) > r: continue found = 0 psum = (0,) * nband # anti-alias for ai in range(antialias): _x = x + ai / float(antialias) for aj in range(antialias): _y = y + aj / float(antialias) u, v = self.warp(_x, _y, r, (cx, cy), (mx, my)) u = int(round(u)) v = int(round(v)) if not (0 <= u < width and 0 <= v < height): continue pt = img.getpixel((u, v)) psum = list(map(operator.add, psum, pt)) found += 1 if found > 0: psum = map(operator.floordiv, psum, (found,) * len(psum)) new_img.putpixel((x, y), tuple(psum)) return new_img
這個類 `LocalWarpEffect` 是一個用於影像處理的Python類,它實現了一種互動式的影像扭曲效果。這種效果通常用於影像編輯軟體中,允許使用者透過滑鼠操作來對影像的特定區域進行平移、縮放和旋轉,而不會失真。下面是對這個類及其方法的逐行解釋:
1-2. 匯入所需的庫,包括OpenCV、imageio、PIL庫中的Image模組、copy模組、operator模組、math模組和numpy。
```python
class LocalWarpEffect(object):
```
3. 定義了一個名為 `LocalWarpEffect` 的類,它繼承自 `object`(在Python 3中,所有類都隱式地繼承自 `object`)。
```python
def __init__(self, center, mouse, radius, antialias=2):
```
4-8. 類的建構函式 `__init__`,用於初始化類的例項。它接受四個引數:
- `center`:區域性變形效果的圓心,通常是滑鼠按下的起點。
- `mouse`:滑鼠釋放的位置。
- `radius`:變形效果作用的半徑。
- `antialias`:抗鋸齒級別,預設為2,用於改善影像質量。
```python
self.center = center
self.mouse = mouse
self.radius = radius
self.antialias = antialias
```
9-12. 將傳入的引數賦值給例項變數。
```python
def warp(self, x, y, r, center, mouse):
```
13. 定義了一個名為 `warp` 的方法,用於計算給定點 `(x, y)` 在經過扭曲後的新位置。它接受四個引數:當前點的座標 `(x, y)` 和之前定義的 `r`、`center` 和 `mouse`。
```python
cx, cy = center
mx, my = mouse
```
14-15. 從 `center` 和 `mouse` 元組中解構出中心點和滑鼠點的座標。
```python
dis_x_c = math.sqrt((x - cx) ** 2 + (y - cy) ** 2)
dis_m_c = math.sqrt((x - mx) ** 2 + (y - my) ** 2)
```
16-17. 分別計算點 `(x, y)` 到中心點和滑鼠點的距離。
```python
div = float(r ** 2 - dis_x_c ** 2 + dis_m_c ** 2)
```
18. 計算一個用於後續計算的除數,如果除數為0,則設定一個非常小的值以避免除以零的錯誤。
```python
factor = ((r ** 2 - dis_x_c ** 2) / div) ** 2
```
19. 計算一個因子,這個因子將用於計算扭曲後的新座標。
```python
u = x - factor * (mx - cx)
v = y - factor * (my - cy)
```
20-21. 根據扭曲演算法計算新座標 `u` 和 `v`。
```python
return u, v
```
22. 返回計算出的新座標。
```python
def __call__(self, img):
```
23. `__call__` 方法允許類的例項像函式一樣被呼叫。它接受一個引數 `img`,即要處理的影像。
```python
width, height = img.size
```
24. 獲取影像的寬度和高度。
```python
new_img = img.copy()
```
25. 建立一個影像的副本,以避免直接修改原始影像。
```python
r = self.radius
cx, cy = self.center
mx, my = self.mouse
```
26-29. 從例項變數中獲取半徑、中心點和滑鼠點的座標。
```python
nband = len(img.getpixel((0, 0)))
```
30. 獲取影像的通道數,例如RGB影像的通道數為3。
```python
antialias = self.antialias
```
31. 獲取抗鋸齒級別。
```python
for x in range(width):
for y in range(height):
```
32-33. 遍歷影像的每個畫素點。
```python
if math.sqrt((x - cx) ** 2 + (y - cy) ** 2) > r:
continue
```
34-35. 如果當前畫素點距離中心點的距離大於半徑,則跳過該點。
```python
found = 0
psum = (0,) * nband
```
36-37. 初始化用於累加畫素值的變數。
```python
for ai in range(antialias):
_x = x + ai / float(antialias)
for aj in range(antialias):
_y = y + aj / float(antialias)
```
38-41. 進行抗鋸齒處理,透過在當前畫素點周圍進行取樣。
```python
u, v = self.warp(_x, _y, r, (cx, cy), (mx, my))
```
42. 對取樣點進行扭曲計算。
```python
u = int(round(u))
v = int(round(v))
```
43-44. 將扭曲後的座標四捨五入到最近的整數。
```python
if not (0 <= u < width and 0 <= v < height):
continue
```
45. 如果扭曲後的座標超出影像邊界,則跳過。
```python
pt = img.getpixel((u, v))
psum = list(map(operator.add, psum, pt))
found += 1
```
46-48. 累加扭曲後的畫素值,並更新取樣點計數。
```python
if found > 0:
psum = map(operator.floordiv, psum, (found,) * len(psum))
new_img.putpixel((x, y), tuple(psum))
```
49-51. 如果有有效的取樣點,則計算平均畫素值,並將其設定為當前畫素點的新值。
```python
return new_img
```
52. 返回處理後的影像。
這個類的主要作用是對影像進行區域性的扭曲處理,透過定義一箇中心點和滑鼠釋放點,以及一個作用半徑,來實現平滑的影像拉伸和扭曲效果。這種效果可以用於影像編輯,例如在不改變影像整體結構的情況下,對人物的體型進行調整。