python - 在 Python 中使用 opencv 加速自定义自适应平滑滤波器
问题描述
我是图像处理方面的新手,并试图实现我在参考书目中找到的自定义过滤器。我需要在 Python 中使用 opencv 来实现它,但我的实现虽然正确,但运行速度非常慢。该算法可以描述如下:
- 计算围绕中心点的 3x3 邻域中的归一化色度距离,
d_i = (|R_centre-R_i|+|G_centre-G_i|+|B_centre-B_i|)/(3x255)
其中中心点是遍历整个图片的当前像素,并且i
是它周围的 8 个点 - 计算出 d_0 到 d_7 的值后,我们计算了一个由 8 个元素组成的数组,称为
c_i = (1-d_i)^10
这将是我们的卷积框中使用的值 - 我们最终的卷积掩码将是
(1/sum(c))*([c_0, c_1, c_2; c_3, 0 , c_4; c_5, c_6, c_7])
这样,基本上c
计算将在周围,中心点将为 0,并且该矩阵将与原始图像中的 9 个像素相乘。 - 最后重复整个过程,尽可能多地声明迭代变量,通常大约 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)
解决方案
您实际上不必为您的任务滑过您的图像。相反,您可以创建图像的所有移动版本,并对它们进行计算。基本上,您将一次性进行相同的计算,而不是遍历所有像素,这需要一些时间。这是一种方法:
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()
该图像经过 4 次平滑处理。我希望代码是不言自明的。
编辑:我们走了。我sum2
在以前的版本中犯了一个错误。我还删除了您的解决方案中的数据类型开关,例如,int
在float
数组c
和d
. 如果您的解决方案需要,请添加它们。
推荐阅读
- r - R写xlsx文件转换数字输出中的空白单元格
- c++ - C++ Libcurl 在较大内容的 readfunction 回调中导致写访问冲突
- merge - 如何在 JGit 中强制合并(使用冲突标记)?
- django - django-oauth-工具包;Django Rest Framework - 未提供身份验证凭据
- javascript - IBM 表单体验外部库错误:jsPDF
- python - 根据其他列的值创建新列
- apache-kafka - HDFS-sink 连接器:没有用于方案的文件系统:http
- algorithm - 算法软件架构
- javascript - 在渲染函数中调用函数 - ReactJS?
- javascript - 回调函数未执行