首页 > 解决方案 > 在 Python 中使用 opencv 加速自定义自适应平滑滤波器

问题描述

我是图像处理方面的新手,并试图实现我在参考书目中找到的自定义过滤器。我需要在 Python 中使用 opencv 来实现它,但我的实现虽然正确,但运行速度非常慢。该算法可以描述如下:

  1. 计算围绕中心点的 3x3 邻域中的归一化色度距离, d_i = (|R_centre-R_i|+|G_centre-G_i|+|B_centre-B_i|)/(3x255)其中中心点是遍历整个图片的当前像素,并且i是它周围的 8 个点
  2. 计算出 d_0 到 d_7 的值后,我们计算了一个由 8 个元素组成的数组,称为c_i = (1-d_i)^10这将是我们的卷积框中使用的值
  3. 我们最终的卷积掩码将是(1/sum(c))*([c_0, c_1, c_2; c_3, 0 , c_4; c_5, c_6, c_7])这样,基本上c计算将在周围,中心点将为 0,并且该矩阵将与原始图像中的 9 个像素相乘。
  4. 最后重复整个过程,尽可能多地声明迭代变量,通常大约 10

对于尺寸为 677x450 的图像,大约需要 1 分钟,我认为这太多了。为了更好地利用 numpy 的功能或其他任何有助于加快速度的方法,有什么可以改变的?

正如我们从照片中看到的那样,即使只进行了 2 次迭代,结果也更加平滑

原始照片 自适应平滑

代码如下:

def adaptive_smoothening(img, iterations):
    M, N, K = img.shape  # M: HEIGHT, N:WIDTH, K:CHANNELS
    F = np.zeros([M, N, K], dtype=np.uint8)
    for p in range(iterations):
        print("Iteration ", p + 1)
        r = img[:, :, 2]
        g = img[:, :, 1]
        b = img[:, :, 0]
        m, n = r.shape  # m: height/channel , n: width/channel
        c = np.zeros([8, 1])
        d = np.zeros([8, 1])
        for i in range(1, m):
            for j in range(1, n):
                # Creating Neighborhood Indices
                ip = i + 1
                im = i - 1
                jm = j - 1
                jp = j + 1
                if im < 1:
                    im = i
                elif ip > m - 1:
                    ip = i - 1
                if jm < 1:
                    jm = j
                elif jp > n - 1:
                    jp = j - 1
                d[0] = (abs(int(r[i, j]) - int(r[i, jm])) + abs(int(g[i, j]) - int(g[i, jm])) + abs(
                    int(b[i, j] - int(b[i, jm])))) / (3 * 255)
                d[1] = (abs(int(r[i, j]) - int(r[i, jp])) + abs(int(g[i, j]) - int(g[i, jp])) + abs(
                    int(b[i, j] - int(b[i, jp])))) / (3 * 255)
                d[2] = (abs(int(r[i, j]) - int(r[ip, j])) + abs(int(g[i, j]) - int(g[ip, j])) + abs(
                    int(b[i, j] - int(b[ip, j])))) / (3 * 255)
                d[3] = (abs(int(r[i, j]) - int(r[im, j])) + abs(int(g[i, j]) - int(g[im, j])) + abs(
                    int(b[i, j] - int(b[im, j])))) / (3 * 255)
                d[4] = (abs(int(r[i, j]) - int(r[im, jm])) + abs(int(g[i, j]) - int(g[im, jm])) + abs(
                    int(b[i, j] - int(b[im, jm])))) / (3 * 255)
                d[5] = (abs(int(r[i, j]) - int(r[ip, jm])) + abs(int(g[i, j]) - int(g[ip, jm])) + abs(
                    int(b[i, j] - int(b[ip, jm])))) / (3 * 255)
                d[6] = (abs(int(r[i, j]) - int(r[ip, jp])) + abs(int(g[i, j]) - int(g[ip, jp])) + abs(
                    int(b[i, j] - int(b[ip, jp])))) / (3 * 255)
                d[7] = (abs(int(r[i, j]) - int(r[im, jp])) + abs(int(g[i, j]) - int(g[im, jp])) + abs(
                    int(b[i, j] - int(b[im, jp])))) / (3 * 255)
                c = [pow(1 - float(x), 10) for x in d]
                sum2 = sum(c)
                F[i, j, 2] = (1 / sum2) * (
                        c[0] * r[i, jm] + c[1] * r[i, jp] + c[2] * r[ip, j] + c[3] * r[im, j] + c[4] * r[im, jm] +
                        c[5] * r[ip, jm] + c[6] * r[ip, jp] + c[7] * r[im, jp])
                F[i, j, 1] = (1 / sum2) * (
                        c[0] * g[i, jm] + c[1] * g[i, jp] + c[2] * g[ip, j] + c[3] * g[im, j] + c[4] * g[im, jm] +
                        c[5] * g[ip, jm] + c[6] * g[ip, jp] + c[7] * g[im, jp])
                F[i, j, 0] = (1 / sum2) * (
                        c[0] * b[i, jm] + c[1] * b[i, jp] + c[2] * b[ip, j] + c[3] * b[im, j] + c[4] * b[im, jm] +
                        c[5] * b[ip, jm] + c[6] * b[ip, jp] + c[7] * b[im, jp])
        img=F
    return F

image = cv2.imread("HorVerTextDoc 001.jpg", 1 )
cv2.imshow("Original", resize(image, 0.5) )
result = adaptive_smoothening(resize(image,0.5),2)
cv2.imshow("Result",result)

标签: pythonimageopencvimage-processingconvolution

解决方案


您实际上不必为您的任务滑过您的图像。相反,您可以创建图像的所有移动版本,并对它们进行计算。基本上,您将一次性进行相同的计算,而不是遍历所有像素,这需要一些时间。这是一种方法:

import numpy as np
import cv2
import matplotlib.pyplot as plt


def adaptive_smooth(img):
    img = np.pad(img,((1,1),(1,1),(0,0)),mode='reflect') # add some padding so translations do not make any problem

    rows,cols = img.shape[:2]

    F = np.zeros_like(img)

    # Translations
    img_lt  = cv2.warpAffine(img,np.float32([[1,0,-1],[0,1,-1]]),(cols,rows)) # top left
    img_t   = cv2.warpAffine(img,np.float32([[1,0,0],[0,1,-1]]),(cols,rows)) # top
    img_rt  = cv2.warpAffine(img,np.float32([[1,0,1],[0,1,-1]]),(cols,rows)) # right top
    img_l   = cv2.warpAffine(img,np.float32([[1,0,-1],[0,1,0]]),(cols,rows)) # left
    img_r   = cv2.warpAffine(img,np.float32([[1,0,1],[0,1,0]]),(cols,rows)) # right
    img_lb  = cv2.warpAffine(img,np.float32([[1,0,-1],[0,1,1]]),(cols,rows)) # left bottom
    img_b   = cv2.warpAffine(img,np.float32([[1,0,0],[0,1,1]]),(cols,rows)) # bottom
    img_rb  = cv2.warpAffine(img,np.float32([[1,0,1],[0,1,1]]),(cols,rows)) # right bottom




    c_0 = (1-(np.sum(np.abs(img-img_lt),axis=2)/(255*3)))**10 
    c_1 = (1-(np.sum(np.abs(img-img_t),axis=2)/(255*3)))**10
    c_2 = (1-(np.sum(np.abs(img-img_rt),axis=2)/(255*3)))**10
    c_3 = (1-(np.sum(np.abs(img-img_l),axis=2)/(255*3)))**10
    c_4 = (1-(np.sum(np.abs(img-img_r),axis=2)/(255*3)))**10
    c_5 = (1-(np.sum(np.abs(img-img_lb),axis=2)/(255*3)))**10
    c_6 = (1-(np.sum(np.abs(img-img_b),axis=2)/(255*3)))**10
    c_7 = (1-(np.sum(np.abs(img-img_rb),axis=2)/(255*3)))**10


    # fig,ax=plt.subplots(1,2,sharex=True,sharey=True)
    # ax[0].imshow(c_0,cmap='gray')
    # ax[1].imshow(c_7,cmap='gray')
    # plt.show()
    sum2 =  c_0 + c_1 + c_2 + c_3 + c_4 + c_5 + c_6 + c_7

    F = (1/np.dstack((sum2,sum2,sum2)))*(img_lt*np.dstack((c_0,c_0,c_0))+
                img_t*np.dstack((c_1,c_1,c_1))+
                img_rt*np.dstack((c_2,c_2,c_2))+
                img_l*np.dstack((c_3,c_3,c_3))+
                img_r*np.dstack((c_4,c_4,c_4))+
                img_lb*np.dstack((c_5,c_5,c_5))+
                img_b*np.dstack((c_6,c_6,c_6))+
                img_rb*np.dstack((c_7,c_7,c_7)))


    return F[1:-1,1:-1,:] # remove padding

img = cv2.cvtColor(cv2.imread("my_image.jpg", 1),cv2.COLOR_BGR2RGB)
F = adaptive_smooth(img) # 1st iteration


for _ in range(3): # 3 more iterations
    F = adaptive_smooth(F)

F[:,:,0] = F[:,:,0]/F[:,:,0].max() # Normalize channels
F[:,:,1] = F[:,:,1]/F[:,:,1].max()
F[:,:,2] = F[:,:,2]/F[:,:,2].max()


fig,ax=plt.subplots(1,2,sharex=True,sharey=True)
ax[0].imshow(img,cmap='gray')
ax[1].imshow((F*255).astype(int),cmap='gray')
plt.show()

Adaptive_smooth_4_times

该图像经过 4 次平滑处理。我希望代码是不言自明的。

编辑:我们走了。我sum2在以前的版本中犯了一个错误。我还删除了您的解决方案中的数据类型开关,例如,intfloat数组cd. 如果您的解决方案需要,请添加它们。


推荐阅读