该算法利用局部的平移、缩放以及旋转的方式来不失真的进行图像纤瘦化处理。

 

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. 返回处理后的图像。

这个类的主要作用是对图像进行局部的扭曲处理,通过定义一个中心点和鼠标释放点,以及一个作用半径,来实现平滑的图像拉伸和扭曲效果。这种效果可以用于图像编辑,例如在不改变图像整体结构的情况下,对人物的体型进行调整。

 

posted @ 2024-06-26 13:16  freedragon  阅读(5)  评论(0编辑  收藏  举报