I once again come to you with a question regarding filters, in this case: Bilateral Filters. I do understand the general concept of it and I did read several sources on the topic (including some questions on stackoverflow). Most sources use this equation to describe the process (I think originally it is from this source, but at this point I am not sure):
With the "general" gaussian filter (that only consideres the space) being represented by this
The Gaussian Filter I did already implement successfully. It is only for gray-scale images and so will the bilateral filter (hopefully) be. It's in no way having a good performance, I am aware, but it does the job. In general I'd think I just need to add the multiplication with G(Ip - Iq) to make it work as a bilateral filter. My issue now is: what exactly does (Ip - Iq) represents? Or asked differently, where do I retrieve those values?
I'm not sure if my code is needed but here's my implementation anyways. The kernel-algorithm I took from this stackoverflow discussion.
def gaussfiltering (img = [], kernelsize=3, sigma=1.9):
rows = len(img)
columns = len(img[0])
kernel = gaussian_kernel(kernelsize, sigma)
horizontallyfiltered = iterate_horizontally(kernel, img, rows, columns, len(kernel))
filtered = iterate_vertically(kernel, horizontallyfiltered, rows, columns, len(kernel))
return filtered
def gaussian_kernel(kernel_size=3, sigma=1.9):
x = numpy.linspace(-sigma, sigma, kernel_size+1)
y = st.norm.cdf(x)
kernel = numpy.diff(y)
return((kernel/kernel.sum()))
def iterate_horizontally (kernel=[], img=[], rows=0, columns=0, kernelsize=0):
horizontallyfiltered = img.copy()
for r in range(rows):
for c in range(columns):
halved = int(kernelsize/2)
if ((c - halved) >= 0 and (c + halved) < columns): #is in range for filter
indexOfImage = c - halved
summed = 0.0
for i in range(kernelsize):
summed += img[r][indexOfImage] * kernel[i]
indexOfImage+=1
horizontallyfiltered[r][c]=summed
return horizontallyfiltered
def iterate_vertically (kernel=[], img=[], rows=0, columns=0, kernelsize=0):
verticallyfiltered = img.copy()
for r in range(rows):
for c in range(columns):
halved = int(kernelsize/2)
if ((r - halved) >= 0 and (r + halved) < rows): #is in range for filter
indexOfImage = r - halved
summed = 0.0
for i in range(kernelsize):
summed += img[indexOfImage][c] * kernel[i]
indexOfImage+=1
verticallyfiltered[r][c]=summed
return verticallyfiltered
EDIT:
It was recommended to run the whole Kernel through the image at once for this, so I rewrote that function to do so (and on its own it still does a fine gaussian filtering). I additionally added a function to calculate the gaussian (without mu since mu=0) of a given X so I could multiply my results with the gaussian of Ip-Iq. However, this causes the entire image to turn incredibly dark - which makes sense the gaussian function returns a value around 0 for pixels that are far away now and thus many of the pixels are dark. So I clearly still got something wrong here and was hoping one of you could point me to it. The gaussian function I tried to replicate:
and the new code:
def iterate_entirely (kernel=[], img=[], rows=0, columns=0, kernelsize=0, sigma=1.9):
filtered = img.copy()
for r in range(rows):
for c in range(columns):
halved = int(kernelsize/2)
if ((c - halved) >= 0 and (c + halved) < columns and (r - halved) >= 0 and (r + halved) < rows): #is in range for filter
indexOfImageRows = r - halved
summed = 0.0
for kr in range(kernelsize):
indexOfImageColumns = c - halved
for kc in range (kernelsize):
ipq = int(img[r][c]) - int(img[indexOfImageRows][indexOfImageColumns])
summed += img[indexOfImageRows][indexOfImageColumns] * kernel[kr][kc] * gaussian(ipq, sigma)
indexOfImageColumns+=1
indexOfImageRows+=1
filtered[r][c]=summed
return filtered
def gaussian(x, sigma):
return 1.0/(numpy.sqrt(2.0*numpy.pi)*sigma)*numpy.exp(-numpy.power((x)/sigma, 2.0)/2)
def gaussian_kernel(kernel_size=3, sigma=1.9):
x = numpy.linspace(-sigma, sigma, kernel_size+1)
y = st.norm.cdf(x)
kernel = numpy.diff(y)
kernel2d = numpy.outer(kernel, kernel)
return (kernel2d/kernel2d.sum())
EDIT 2:
more recommended changes, new code:
def iterate_entirely (kernel=[], img=[], rows=0, columns=0, kernelsize=0, sigma=1.9):
filtered = img.copy()
for r in range(rows):
for c in range(columns):
halved = int(kernelsize/2)
if ((c - halved) >= 0 and (c + halved) < columns and (r - halved) >= 0 and (r + halved) < rows): #is in range for filter
indexOfImageRows = r - halved
summed = 0.0
norm = 0.0
for kr in range(kernelsize):
indexOfImageColumns = c - halved
for kc in range (kernelsize):
ipq = int(img[r][c]) - int(img[indexOfImageRows][indexOfImageColumns])
multiplicator = kernel[kr][kc] * gaussian(ipq, sigma)
summed += img[indexOfImageRows][indexOfImageColumns] * multiplicator
norm += multiplicator
indexOfImageColumns+=1
indexOfImageRows+=1
print (" summed: ", summed, " norm: ", norm, " normed : ", summed/norm)
filtered[r][c]=summed/norm
return filtered
def gaussian(x, sigma):
return numpy.exp(-numpy.power((x)/sigma, 2.0)/2)