Bokeh与Numba结合实现交互式图像处理教程

Bokeh与Numba结合实现交互式图像处理教程

bokeh bokeh/bokeh: 是一个用于创建交互式图形和数据的 Python 库。适合用于数据可视化、数据分析和呈现,以及创建动态的 Web 应用。特点是提供了一种简洁、直观的 API 来描述和处理数据,并生成交互式的可视化效果。 bokeh 项目地址: https://gitcode.com/gh_mirrors/bo/bokeh

概述

本教程将展示如何利用Bokeh可视化库与Numba加速计算库,在Jupyter Notebook中实现高效的交互式图像处理。通过这个教程,你将学习到:

  1. 如何使用Bokeh在Notebook中展示图像
  2. 如何利用Numba加速图像处理算法
  3. 如何实现无服务器(serverless)的交互式图像处理

环境准备

在开始之前,请确保已安装以下Python库:

  • Bokeh:用于创建交互式可视化
  • Numba:用于加速数值计算
  • NumPy:用于数组操作
  • SciPy:提供示例图像数据
  • ipywidgets:用于创建交互控件

基础图像处理:高斯模糊

1. 加载和显示图像

首先,我们加载一张示例图像并显示在Bokeh画布上:

from bokeh.plotting import figure, show, output_notebook
from bokeh.models import GlyphRenderer
import numpy as np
import scipy.misc

# 加载并预处理图像
img_blur = (scipy.misc.ascent()[::-1,:]/255.0)[:250, :250].copy(order='C')

# 创建灰度调色板
palette = [f'#{i:02x}{i:02x}{i:02x}' for i in range(256)]

# 创建Bokeh图像展示
width, height = img_blur.shape
p_blur = figure(x_range=(0, width), y_range=(0, height))
r_blur = p_blur.image(image=[img_blur], x=[0], y=[0], dw=[width], dh=[height], palette=palette, name='blur')

# 显示图像
t_blur = show(p_blur, notebook_handle=True)

2. 使用Numba加速高斯模糊算法

我们使用Numba的@njit装饰器来加速高斯模糊算法:

from numba import njit

@njit
def blur(outimg, img, amt):
    iw, ih = img.shape
    for i in range(amt, iw-amt):
        for j in range(amt, ih-amt):
            px = 0.
            for w in range(-amt//2, amt//2):
                for h in range(-amt//2, amt//2):
                    px += img[i+w, j+h]
            outimg[i, j]= px/(amt*amt)

3. 创建交互控件

通过ipywidgets创建滑块控件,实现交互式模糊效果:

from ipywidgets import interact
from bokeh.io import push_notebook

def update(i=0):
    level = 2*i + 1
    out = img_blur.copy()
    
    # 应用模糊效果
    blur(out, img_blur, level)
    
    # 更新Bokeh显示
    r_blur.data_source.data['image'] = [out]
    push_notebook(handle=t_blur)

# 创建滑块控件
interact(update, i=(0, 10))

进阶应用:3x3图像卷积核

1. 卷积核工厂函数

我们创建一个通用的卷积核应用函数,支持边缘处理:

from numba import jit

@jit
def getitem(img, x, y):
    # 处理边缘像素
    w, h = img.shape
    if x >= w:
        x = w - 1 - (x - w)
    if y >= h:
        y = h - 1 - (y - h)
    return img[x, y]

def filter_factory(kernel):
    # 归一化卷积核
    ksum = np.sum(kernel)
    if ksum == 0:
        ksum = 1
    k9 = kernel / ksum

    @jit
    def kernel_apply(img, out, x, y):
        # 内部像素处理
        tmp = 0
        for i in range(3):
            for j in range(3):
                tmp += img[x+i-1, y+j-1] * k9[i, j]
        out[x, y] = tmp

    @jit
    def kernel_apply_edge(img, out, x, y):
        # 边缘像素处理
        tmp = 0
        for i in range(3):
            for j in range(3):
                tmp += getitem(img, x+i-1, y+j-1) * k9[i, j]
        out[x, y] = tmp

    @jit
    def kernel_k9(img, out):
        # 应用卷积核到整个图像
        # 处理内部区域
        for x in range(1, img.shape[0] -1):
            for y in range(1, img.shape[1] -1):
                kernel_apply(img, out, x, y)

        # 处理边缘区域
        for x in range(img.shape[0]):
            kernel_apply_edge(img, out, x, 0)
            kernel_apply_edge(img, out, x, img.shape[1] - 1)

        for y in range(img.shape[1]):
            kernel_apply_edge(img, out, 0, y)
            kernel_apply_edge(img, out, img.shape[0] - 1, y)

    return kernel_k9

2. 常用卷积核示例

我们定义了几种常见的图像处理卷积核:

# 平均模糊
average = np.array([
    [1, 1, 1],
    [1, 1, 1],
    [1, 1, 1],
], dtype=np.float32)

# 锐化
sharpen = np.array([
    [-1, -1, -1],
    [-1, 12, -1],
    [-1, -1, -1],
], dtype=np.float32)

# 边缘检测
edge = np.array([
    [ 0, -1,  0],
    [-1,  4, -1],
    [ 0, -1,  0],
], dtype=np.float32)

# 其他卷积核...

3. 交互式卷积应用

创建交互界面,允许用户选择不同的卷积核和调整参数:

def update(image="ascent", kernel_name="none", scale=100, bias=0):
    img_kernel = images.get(image)
    
    # 应用选择的卷积核
    kernel = kernels.get(kernel_name, None)
    if kernel is None:
        out = np.copy(img_kernel)
    else:
        out = np.zeros_like(img_kernel)
        kernel(img_kernel, out)
    
    # 调整亮度和对比度
    out *= scale / 100.0
    out += bias
    
    # 更新显示
    r_kernel.data_source.data['image'] = [out]
    push_notebook(handle=t_kernel)

# 创建交互控件
knames = ["none", *sorted(kernels.keys())]
interact(update, image=["ascent" ,"face"], kernel_name=knames, scale=(10, 100, 10), bias=(0, 255))

高级应用:小波分解

1. Haar小波变换实现

我们使用Numba加速Haar小波变换:

@njit
def wavelet_decomposition(img, tmp):
    """
    使用tmp作为临时缓冲区对img进行小波分解
    """
    w, h = img.shape
    halfwidth, halfheight = w//2, h//2

    lefthalf, righthalf = tmp[:halfwidth, :], tmp[halfwidth:, :]

    # 沿第一维度分解
    for x in range(halfwidth):
        for y in range(h):
            lefthalf[x, y] = (img[2 * x, y] + img[2 * x + 1, y]) / 2
            righthalf[x, y] = img[2 * x, y] - img[2 * x + 1, y]

    # 交换缓冲区
    img, tmp = tmp, img
    tophalf, bottomhalf = tmp[:, :halfheight], tmp[:, halfheight:]

    # 沿第二维度分解
    for y in range(halfheight):
        for x in range(w):
            tophalf[x, y] = (img[x, 2 * y] + img[x, 2 * y + 1]) / 2
            bottomhalf[x, y] = img[x, 2 * y] - img[x, 2 * y + 1]

    return halfwidth, halfheight

2. 交互式小波分解

创建滑块控件,控制小波分解的层级:

def update(level=0):
    out = np.copy(img_wavelet)
    tmp = np.zeros_like(img_wavelet)

    hw, hh = img_wavelet.shape
    while level > 0 and hw > 1 and hh > 1:
        hw, hh = wavelet_decomposition(out[:hw, :hh], tmp[:hw, :hh])
        level -= 1

    r_wavelet.data_source.data['image'] = [out]
    push_notebook(handle=t_wavelet)

interact(update, level=(0, 7))

性能优化技巧

  1. Numba使用建议

    • 使用@njit替代@jit以获得更好的性能
    • 确保数组是连续的(使用order='C'
    • 避免在Numba函数中分配大量内存
  2. Bokeh交互优化

    • 使用push_notebook进行高效更新
    • 避免频繁更新,可以添加去抖动(debounce)机制
    • 对于复杂操作,考虑使用Bokeh服务器应用
  3. 图像处理优化

    • 预处理图像到合适的大小
    • 对多次操作的结果进行缓存
    • 分离耗时操作和快速操作

总结

本教程展示了如何结合Bokeh和Numba在Jupyter Notebook中创建高效的交互式图像处理应用。通过这种组合,我们能够:

  1. 利用Numba加速计算密集型图像处理算法
  2. 使用Bokeh创建丰富的可视化界面
  3. 通过ipywidgets添加交互控件
  4. 实现无服务器的交互式体验

这种技术组合特别适合原型开发、教学演示和数据分析场景,能够快速实现想法并验证算法效果。

bokeh bokeh/bokeh: 是一个用于创建交互式图形和数据的 Python 库。适合用于数据可视化、数据分析和呈现,以及创建动态的 Web 应用。特点是提供了一种简洁、直观的 API 来描述和处理数据,并生成交互式的可视化效果。 bokeh 项目地址: https://gitcode.com/gh_mirrors/bo/bokeh

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高崴功Victorious

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值