【发布时间】:2015-03-17 14:34:07
【问题描述】:
我在 Python 中实现了一种算法,用于减少图像中的强度变化(闪烁)。该算法首先计算图像每一行的累积直方图。然后,它使用高斯核对垂直方向(跨列)的累积行累积直方图进行过滤,从而减少行累积直方图之间的差异。在最后一部分,原始图像的每一行累积直方图应该与对应得到的经过高斯滤波的行累积直方图相匹配。因此,执行直方图匹配操作(每行),并重建所需的行。自然地,最终通过简单地将所有行垂直堆叠在一起来重建图像。
在我的代码中,最后一部分相互之间有两个 for 循环(针对每个强度级别 [0,255] 对每一行和每一行内部进行迭代)需要大量时间,因此使用该算法不再可行。对于单个 4592x3448 (16MP) 图像,在我的机器上执行时间超过 10 分钟。当然,为 3448 行中的每一行迭代超过 256 个强度值应该会大大减慢算法的速度,但由于算法的性质,我看不出有任何其他方法可以避免这些 for 循环。
我对 Python 很陌生,所以我在这里的编程方面可能犯了严重的罪行。我将不胜感激任何提示和代码审查。您可以在此链接下找到示例图像: http://s3.postimg.org/a17b3otpf/00000_cam0.jpg
import time
import cv2
import numpy as np
import scipy.ndimage as ndi
from matplotlib import pyplot as plt
start_time = time.time()
### Algorithm: Filtering row cumulative histograms with different Gaussian variances
T = 200 # threshold
img = cv2.imread('flicker.jpg',0)
rows,cols = img.shape
cdf_hist = np.zeros((rows,256))
for i in range(0,rows):
# Read one row
img_row = img[i,]
# Calculate the row histogram
hist_row = cv2.calcHist([img_row],[0],None,[256],[0,256])
# Calculate the cumulative row histogram
cdf_hist_row = hist_row.cumsum()
# Accumulate the cumulative histogram of each row
cdf_hist[i,:] = cdf_hist_row
# Apply Gaussian filtering on the row cumulative histograms along the columns (vertically)
# For dark pixels, use higher sigma
Gauss1_cdf = ndi.gaussian_filter1d(cdf_hist, sigma=6, axis=0, output=np.float64, mode='nearest')
# For bright pixel, use lower sigma
Gauss2_cdf = ndi.gaussian_filter1d(cdf_hist, sigma=3, axis=0, output=np.float64, mode='nearest')
##
print("--- %s seconds ---" % (time.time() - start_time))
### UNTIL HERE: it takes in my computer approx. 0.25 sec with a 16MP image
### This part takes too much time ###### START ######################
# Perform histogram matching (for each row) to either 'Hz1' or 'Hz2'
img_match = np.copy(img)
for r in range(0,rows):
row = img[r,:]
Hy = cdf_hist[r,:] # Original row histogram
Hz1 = Gauss1_cdf[r,:] # Histogram 1 to be matched
Hz2 = Gauss2_cdf[r,:] # Histogram 2 to be matched
row_match = img_match[r,:]
for i in range(0,255): # for each intensity value
# Find the indices of the pixels in the row whose intensity = i
ind = [m for (m,val) in enumerate(row) if val==i]
j = Hy[i]
while True:
# use the appropriate CDF (Hz1 or Hz2) according to the bin number
if i<T:
k = [m for (m,val) in enumerate(Hz1) if val>j-1 and val<j+1]
else:
k = [m for (m,val) in enumerate(Hz2) if val>j-1 and val<j+1]
if len(k)>0:
break
else:
j = j+1
row_match[ind] = k[0]
###################### END ####################################
# Set upper bound to the change of intensity values to avoid brightness overflows etc.
alfa = 5
diff_img = cv2.absdiff(img,img_match)
img_match2 = np.copy(img_match)
img_match2[diff_img>alfa] = img[diff_img>alfa] + alfa
## Plots
plt.subplot(121), plt.imshow(img,'gray')
plt.subplot(122), plt.imshow(img_match2, 'gray')
plt.show()
print("--- %s seconds ---" % (time.time() - start_time))
【问题讨论】:
-
这将是一个更好的地方来提出您的问题:codereview.stackexchange.com 在这里提出问题的一个问题是,人们普遍希望这个问题有一个单一的答案。你的问题不够清楚,只有一个答案。我可能会看到一个错误。其他人可能会看到另一个...
-
我假设 time.time() 被用来衡量计算需要多长时间?更好的方法是使用 timeit。
-
而不是
if len(k)>0:,您可以使用if k:,但无论如何您都不应该定义k。请参阅下一条评论。 -
它看起来像这里:
k = [m for (m,val) in enumerate(Hz2) if val>j-1 and val<j+1]你只想找到j是否出现在Hz2中,稍后你想知道它出现的第一个位置(我假设它必须是一个int )。所以首先,只需用if j in Hz2:替换k=..., if len(k)>0:。然后做row_match[ind] = Hz2.index(j) -
我会给出一个解决方案——但如果我能理解
ind是什么就更好了。它看起来像是一个列表,但它也被用作索引?
标签: python algorithm image-processing histogram