玩转图像滤镜:从色彩调整到卡通化及实时应用
立即解锁
发布时间: 2025-09-13 01:58:18 阅读量: 2 订阅数: 19 AIGC 

### 玩转图像滤镜:从色彩调整到卡通化及实时应用
#### 1. 灰度图像滤镜应用
要对灰度输入图像应用滤镜,我们需要先确定一组锚点 `(xi, yi)`。以下是具体的代码实现:
```python
import cv2
import numpy as np
x = [0, 128, 255]
y = [0, 192, 255]
myLUT = spline_to_lookup_table(x, y)
img_curved = cv2.LUT(img_gray, myLUT).astype(np.uint8)
```
这里,`spline_to_lookup_table` 函数用于生成查找表,`cv2.LUT` 函数将查找表应用到灰度图像上。
#### 2. 设计暖色调和冷色调效果
为了实现图像的暖色调和冷色调效果,我们可以定义两个通用的曲线滤镜:一个用于增加通道的像素值,另一个用于减少通道的像素值。
```python
INCREASE_LOOKUP_TABLE = spline_to_lookup_table([0, 64, 128, 192, 256],
[0, 70, 140, 210, 256])
DECREASE_LOOKUP_TABLE = spline_to_lookup_table([0, 64, 128, 192, 256],
[0, 30, 80, 120, 192])
```
接下来,我们需要将 RGB 图像分解为不同的通道,并对每个通道应用滤镜。以下是一个辅助函数:
```python
def apply_rgb_filters(rgb_image, *,
red_filter=None, green_filter=None,
blue_filter=None):
c_r, c_g, c_b = cv2.split(rgb_image)
if red_filter is not None:
c_r = cv2.LUT(c_r, red_filter).astype(np.uint8)
if green_filter is not None:
c_g = cv2.LUT(c_g, green_filter).astype(np.uint8)
if blue_filter is not None:
c_b = cv2.LUT(c_b, blue_filter).astype(np.uint8)
return cv2.merge((c_r, c_g, c_b))
```
##### 2.1 实现暖色调效果
要使图像呈现出炎热、阳光明媚的效果,可以通过以下两个步骤实现:
1. 增加 RGB 图像中 R 通道的像素值,减少 B 通道的像素值。
```python
interim_img = apply_rgb_filters(rgb_image,
red_filter=INCREASE_LOOKUP_TABLE,
blue_filter=DECREASE_LOOKUP_TABLE)
```
2. 将图像转换为 HSV 颜色空间,并增加 S 通道的像素值。
```python
def apply_hue_filter(rgb_image, hue_filter):
c_h, c_s, c_v = cv2.split(cv2.cvtColor(rgb_image, cv2.COLOR_RGB2HSV))
c_s = cv2.LUT(c_s, hue_filter).astype(np.uint8)
return cv2.cvtColor(cv2.merge((c_h, c_s, c_v)), cv2.COLOR_HSV2RGB)
```
##### 2.2 实现冷色调效果
冷色调效果的实现与暖色调类似,只是增加 B 通道的像素值,减少 R 通道的像素值,并减少 S 通道的像素值。
```python
def _render_cool(rgb_image: np.ndarray) -> np.ndarray:
interim_img = apply_rgb_filters(rgb_image,
red_filter=DECREASE_LOOKUP_TABLE,
blue_filter=INCREASE_LOOKUP_TABLE)
return apply_hue_filter(interim_img, DECREASE_LOOKUP_TABLE)
```
#### 3. 图像卡通化
要将 RGB 彩色图像转换为卡通风格,可以按照以下步骤进行:
1. **应用双边滤波器**:减少图像的颜色调色板。
2. **将原始彩色图像转换为灰度图像**。
3. **应用中值模糊**:减少图像噪声。
4. **使用自适应阈值处理**:检测并强调边缘。
5. **合并颜色图像和边缘掩码**。
以下是具体的代码实现:
```python
def cartoonize(rgb_image, *,
num_pyr_downs=2, num_bilaterals=7):
# STEP 1 -- Apply a bilateral filter to reduce the color palette of the image.
downsampled_img = rgb_image
for _ in range(num_pyr_downs):
downsampled_img = cv2.pyrDown(downsampled_img)
for _ in range(num_bilaterals):
filterd_small_img = cv2.bilateralFilter(downsampled_img, 9, 9, 7)
filtered_normal_img = filterd_small_img
for _ in range(num_pyr_downs):
filtered_normal_img = cv2.pyrUp(filtered_normal_img)
# make sure resulting image has the same dims as original
if filtered_normal_img.shape != rgb_image.shape:
filtered_normal_img = cv2.resize(filtered_normal_img, rgb_image.shape[:2])
# STEP 2 -- Convert the original color image into grayscale.
img_gray = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2GRAY)
# STEP 3 -- Apply a median blur to reduce image noise.
img_blur = cv2.medianBlur(img_gray, 7)
# STEP 4 -- Use adaptive thresholding to detect and emphasize the edges in an edge mask.
gray_edges = cv2.adaptiveThreshold(img_blur, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 9, 2)
# STEP 5 -- Combine the color image from step 1 with the edge mask from step 4.
rgb_edges = cv2.cvtColor(gray_edges, cv2.COLOR_GRAY2RGB)
return cv2.bitwise_and(filtered_normal_img, rgb_edges)
```
#### 4. 双边滤波器的使用
双边滤波器适用于将 RGB 图像转换为彩色绘画或卡通风格,因为它可以平滑平坦区域,同时保持边缘清晰。但它的计算成本较高,为了降低计算成本,可以采取以下措施:
1. **降低图像分辨率**:使用 `cv2.resize` 或 `cv2.pyrDown` 函数。
```python
# 使用 cv2.resize
img_small = cv2.resize(img_rgb, (0, 0), fx=0.5, fy=0.5)
# 使用 cv2.pyrDown
downsampled_img = cv2.pyrDown(rgb_image)
```
2. **多次应用小的双边滤波器**:
```python
for _ in range(num_bilaterals):
filterd_small_img = cv2.bilateralFilter(downsampled_img, 9, 9, 7)
```
3. **将图像恢复到原始大小**:使用 `cv2.pyrUp` 函数。
```python
filtered_normal_img = filterd_small_img
for _ in range(num_pyr_downs):
filtered_normal_img = cv2.pyrUp(filtered_normal_img)
```
#### 5. 边缘检测
在边缘检测中,我们选择 `cv2.adaptiveThreshold` 函数,因为它对光照条件具有很强的鲁棒性。具体步骤如下:
1. **将 RGB 图像转换为灰度图像**:
```python
img_gray = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2GRAY)
```
2. **应用中值模糊**:
```python
img_blur = cv2.medianBlur(img_gray, 7)
```
3. **使用自适应阈值处理**:
```python
gray_edges = cv2.adaptiveThreshold(img_blur, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 9, 2)
```
#### 6. 构建交互式应用程序
为了实时应用这些滤镜,我们需要构建一个交互式应用程序。具体步骤如下:
1. **导入必要的模块**:
```python
import wx
import cv2
import numpy as np
from wx_gui import BaseLayout
from tools import apply_hue_filter
from tools import apply_rgb_filters
from tools import load_img_resized
from tools import spline_to_lookup_table
from tools import cartoonize
from tools import pencil_sketch_on_canvas
```
2. **设置相机捕获**:
```python
def main():
capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
```
3. **构建 GUI 应用程序**:
```python
app = wx.App()
layout = FilterLayout(capture, title='Fun with Filters')
layout.Center()
layout.Show()
app.MainLoop()
```
#### 7. GUI 基础类
`BaseLayout` 类是一个抽象基类,作为所有 GUI 布局的蓝图。它包含一个抽象方法 `process_frame`,任何派生类都必须实现该方法。
```python
import numpy as np
import wx
import cv2
class BaseLayout(wx.Frame):
def process_frame(self, frame_rgb: np.ndarray) -> np.ndarray:
"""Process the frame of the camera (or other capture device)
:param frame_rgb: Image to process in rgb format, of shape (H, W, 3)
:return: Processed image in rgb format, of shape (H, W, 3)
"""
raise NotImplementedError()
```
#### 8. GUI 构造函数
`BaseLayout` 类的构造函数接受相机捕获对象、标题、父窗口、窗口 ID 和帧率等参数。在构造函数中,首先读取一帧图像以确定图像大小。
```python
def __init__(self,
capture: cv2.VideoCapture,
title: str = None,
parent=None,
window_id: int = -1, # default value
fps: int = 10):
self.capture = capture
_, frame = self._acquire_frame()
self.imgHeight, self.imgWidth = frame.shape[:2]
```
### 总结
通过以上步骤,我们可以实现图像的暖色调、冷色调和卡通化效果,并构建一个交互式应用程序,实时应用这些滤镜。以下是整个图像滤镜处理流程的 mermaid 流程图:
```mermaid
graph LR
A[输入 RGB 图像] --> B{选择滤镜类型}
B --> |暖色调| C[增加 R 通道像素值,减少 B 通道像素值]
C --> D[转换为 HSV 颜色空间,增加 S 通道像素值]
B --> |冷色调| E[增加 B 通道像素值,减少 R 通道像素值]
E --> F[转换为 HSV 颜色空间,减少 S 通道像素值]
B --> |卡通化| G[应用双边滤波器]
G --> H[转换为灰度图像]
H --> I[应用中值模糊]
I --> J[使用自适应阈值处理]
J --> K[合并颜色图像和边缘掩码]
D --> L[输出处理后图像]
F --> L
K --> L
```
同时,我们还可以通过表格总结不同滤镜的实现步骤:
| 滤镜类型 | 实现步骤 |
| ---- | ---- |
| 暖色调 | 1. 增加 R 通道像素值,减少 B 通道像素值<br>2. 转换为 HSV 颜色空间,增加 S 通道像素值 |
| 冷色调 | 1. 增加 B 通道像素值,减少 R 通道像素值<br>2. 转换为 HSV 颜色空间,减少 S 通道像素值 |
| 卡通化 | 1. 应用双边滤波器<br>2. 转换为灰度图像<br>3. 应用中值模糊<br>4. 使用自适应阈值处理<br>5. 合并颜色图像和边缘掩码 |
这样,我们就可以根据不同的需求选择合适的滤镜,并通过代码实现相应的效果。
### 玩转图像滤镜:从色彩调整到卡通化及实时应用
#### 9. 深入理解双边滤波器
双边滤波器在图像卡通化过程中起着关键作用。它能够在平滑图像的同时保留边缘信息,这是其他平滑滤波器(如高斯模糊)所不具备的优势。然而,其高计算成本是一个明显的缺点。
为了更直观地理解双边滤波器的参数对图像的影响,我们来看一下 `cv2.bilateralFilter` 函数的参数:
- `d`:表示像素邻域的直径。较大的 `d` 值会使滤波器考虑更多的像素,从而产生更平滑的效果,但也会增加计算时间。
- `sigmaColor`:颜色空间的标准差。它控制着颜色相似度对滤波的影响。较大的 `sigmaColor` 值会使颜色相近的像素更容易被平滑。
- `sigmaSpace`:坐标空间的标准差。它控制着空间距离对滤波的影响。较大的 `sigmaSpace` 值会使距离相近的像素更容易被平滑。
在实际应用中,我们可以根据具体需求调整这些参数。例如,在进行图像卡通化时,我们使用的参数是 `d=9`,`sigmaColor=9`,`sigmaSpace=7`,这些参数可以在保留边缘的同时,有效地减少颜色调色板。
#### 10. 自适应阈值处理的优势
在边缘检测中,我们选择了 `cv2.adaptiveThreshold` 函数,而不是其他常见的边缘检测算法(如 Canny 边缘检测、Sobel 算子等)。这是因为自适应阈值处理具有很强的光照鲁棒性。
传统的阈值处理方法(如 `cv2.threshold`)使用一个全局的阈值来将图像转换为二进制图像,这在光照不均匀的情况下效果不佳。而自适应阈值处理会在每个小邻域内独立地检测最显著的特征,不考虑全局图像特征,因此对光照条件具有很强的适应性。
然而,自适应阈值处理也容易受到噪声的影响。为了减少噪声的干扰,我们在进行自适应阈值处理之前,先对图像进行了中值模糊。中值模糊会用邻域内像素值的中值来替换当前像素值,从而有效地减少噪声。
以下是一个简单的对比表格,展示了不同边缘检测算法的特点:
| 算法名称 | 优点 | 缺点 |
| ---- | ---- | ---- |
| Canny 边缘检测 | 相对简单有效 | 易受噪声影响 |
| Sobel 算子 | 可减少噪声影响 | 不具有旋转对称性 |
| Scharr 算子 | 修正了 Sobel 算子的旋转对称性问题 | 只考虑一阶导数 |
| 自适应阈值处理 | 对光照条件鲁棒 | 易受噪声影响 |
#### 11. 优化交互式应用程序
在构建交互式应用程序时,我们还可以进行一些优化,以提高应用程序的性能和用户体验。
##### 11.1 帧率优化
为了确保应用程序能够实时运行,我们限制了视频流的大小为 640 x 480 像素。此外,我们还可以通过调整帧率来平衡性能和流畅度。在 `BaseLayout` 类的构造函数中,我们可以根据实际情况调整 `fps` 参数。
##### 11.2 内存管理
在处理视频流时,内存管理非常重要。我们可以在每次处理完一帧图像后,及时释放不再使用的内存。例如,在 `process_frame` 方法中,我们可以使用 `del` 关键字删除不再使用的变量。
##### 11.3 用户界面优化
我们可以使用 wxPython 提供的丰富组件来优化用户界面。例如,添加更多的按钮来选择不同的滤镜,或者添加滑块来调整滤镜的强度。
以下是一个优化后的 `BaseLayout` 类的示例代码:
```python
import numpy as np
import wx
import cv2
class BaseLayout(wx.Frame):
def __init__(self,
capture: cv2.VideoCapture,
title: str = None,
parent=None,
window_id: int = -1, # default value
fps: int = 10):
self.capture = capture
_, frame = self._acquire_frame()
self.imgHeight, self.imgWidth = frame.shape[:2]
self.fps = fps
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
self.timer.Start(1000 // self.fps)
def _acquire_frame(self):
ret, frame = self.capture.read()
return ret, frame
def on_timer(self, event):
ret, frame = self._acquire_frame()
if ret:
processed_frame = self.process_frame(frame)
# 显示处理后的图像
self.show_frame(processed_frame)
def process_frame(self, frame_rgb: np.ndarray) -> np.ndarray:
"""Process the frame of the camera (or other capture device)
:param frame_rgb: Image to process in rgb format, of shape (H, W, 3)
:return: Processed image in rgb format, of shape (H, W, 3)
"""
raise NotImplementedError()
def show_frame(self, frame):
# 显示图像的代码
pass
```
#### 12. 拓展应用场景
除了实现暖色调、冷色调和卡通化效果外,我们还可以拓展这些技术的应用场景。
##### 12.1 艺术创作
我们可以将这些滤镜应用于艺术创作中,例如生成独特风格的绘画作品。通过调整滤镜的参数,我们可以创造出不同的艺术效果。
##### 12.2 视频编辑
在视频编辑中,我们可以实时应用这些滤镜,为视频增添不同的氛围。例如,在拍摄旅游视频时,我们可以应用暖色调滤镜来营造阳光明媚的感觉。
##### 12.3 游戏开发
在游戏开发中,我们可以使用这些滤镜来实现不同的视觉效果。例如,在恐怖游戏中,我们可以应用冷色调滤镜来营造阴森的氛围。
### 总结
通过本文的介绍,我们学习了如何使用 OpenCV 实现图像的暖色调、冷色调和卡通化效果,并构建了一个交互式应用程序来实时应用这些滤镜。我们深入探讨了双边滤波器、自适应阈值处理等关键技术的原理和应用,同时还介绍了一些优化方法和拓展应用场景。
以下是整个图像滤镜处理和应用的 mermaid 流程图:
```mermaid
graph LR
A[输入 RGB 图像] --> B{选择滤镜类型}
B --> |暖色调| C[增加 R 通道像素值,减少 B 通道像素值]
C --> D[转换为 HSV 颜色空间,增加 S 通道像素值]
B --> |冷色调| E[增加 B 通道像素值,减少 R 通道像素值]
E --> F[转换为 HSV 颜色空间,减少 S 通道像素值]
B --> |卡通化| G[应用双边滤波器]
G --> H[转换为灰度图像]
H --> I[应用中值模糊]
I --> J[使用自适应阈值处理]
J --> K[合并颜色图像和边缘掩码]
D --> L[输出处理后图像]
F --> L
K --> L
L --> M[应用于交互式应用程序]
M --> N{选择应用场景}
N --> |艺术创作| O[生成艺术作品]
N --> |视频编辑| P[为视频增添氛围]
N --> |游戏开发| Q[实现游戏视觉效果]
```
希望本文能够帮助你更好地理解图像滤镜处理技术,并激发你在实际应用中的创意。通过不断地尝试和调整,你可以创造出更加独特和精彩的图像效果。
0
0
复制全文
相关推荐









