I have two filters: (1) Median Filter and (2) Adaptive Median Filter
My median filter works. It takes an image, creates a padding the kernel convolves, replacing the center pixel with the median value found in each kernel window.
My adaptive median filter does not work. The difference between this one and the first one is that I want my adaptive median filter to iterate through the image block by block, instead of pixel by pixel, replacing the outliers in each kernel window with the median value. I think my logic is correct in my adaptive median, but I'm having trouble lining everything up in my output, especially with the dimensions of the image requiring the padding.
Also, is there a way to not include the padding when calculating the median near the edges?
Had to change the main for loop:
My median filter works. It takes an image, creates a padding the kernel convolves, replacing the center pixel with the median value found in each kernel window.
My adaptive median filter does not work. The difference between this one and the first one is that I want my adaptive median filter to iterate through the image block by block, instead of pixel by pixel, replacing the outliers in each kernel window with the median value. I think my logic is correct in my adaptive median, but I'm having trouble lining everything up in my output, especially with the dimensions of the image requiring the padding.
Also, is there a way to not include the padding when calculating the median near the edges?
import cv2 import numpy as np from matplotlib import pyplot as plt import math import sys from skimage.exposure import rescale_intensity np.set_printoptions(threshold=sys.maxsize) # PART 2: ADAPTIVE MEDIAN FILTER # load image image = cv2.imread('2_noise.png',0) image2 = cv2.imread('2_noise.png',0) # convolve function def medianFilter(image, kernel): # size of image and kernel (iH, iW) = image.shape[:2] (kH, kW) = kernel.shape[:2] print(iH, iW, kH, kW) # add padding to input image pad = (kW - 1) // 2 image = cv2.copyMakeBorder(image, pad, pad, pad, pad, cv2.BORDER_REPLICATE) # allocate memory for the output image output = np.zeros((iH, iW), dtype="float32") # loop over the input image for y in np.arange(pad, iH + pad): for x in np.arange(pad, iW + pad): # extract the *center* region of the current (x, y)-coordinates dimensions roi = image[y - pad:y + pad + 1, x - pad:x + pad + 1] # convolution k = np.median(roi*kernel) # store the convolved value in the output(x,y) output[y - pad, x - pad] = k # rescale the output image output = rescale_intensity(output, in_range=(0, 255)) output = (output * 255).astype("uint8") # return the output image return output def iqr(a, outlierConstant): """ a : numpy.ndarray (array from which outliers have to be removed.) outlierConstant : (scale factor around interquartile region.) """ num = a.shape[0] upper_quartile = np.percentile(a, 75) lower_quartile = np.percentile(a, 25) IQR = (upper_quartile - lower_quartile) * outlierConstant quartileSet = (lower_quartile - IQR, upper_quartile + IQR) outlier_indx = [] for i in range(num): if np.any(a[i] >= quartileSet[0]) and np.any(a[i] <= quartileSet[1]): pass else: outlier_indx += [i] return outlier_indx def function(arrayMatrix, threshold=.5): zscore = (arrayMatrix - arrayMatrix.mean())/arrayMatrix.std() return np.where(np.abs(zscore) > threshold) def adaptiveMedian(image, kernel): # size of image and kernel (iH, iW) = image.shape[:2] (kH, kW) = kernel.shape[:2] print('Image Size: ', iH, iW) print('Kernel Size: ', kH, kW) # add padding to input image pad = (kW - 1) // 2 image = cv2.copyMakeBorder(image, pad, pad, pad, pad, cv2.BORDER_REPLICATE) # allocate memory for the output image output = np.zeros((iH+pad*2, iW+pad*2), dtype="float32") yRange = np.arange(pad, iH + pad) for xxx in yRange[::7]: print(xxx) # loop over the input image for y in yRange[::7]: for x in yRange[::7]: #print(np.arange(pad, iH + pad)) # extract the *center* region of the current (x, y)-coordinates dimensions roi = image[y - pad:y + pad + 1, x - pad:x + pad + 1] #print('roi: ', roi) # finding median median = np.median(roi) # finding outliers & reshaping outlier = function(roi) out = np.asarray(outlier,order=2) rowss = out.shape[0] colss = out.shape[1] xx = out[0] yy = out[1] data = np.array((xx,yy)).T # replacing outlier pixels with median value Range = len(data) for xx in range(0,Range): xCoord = data[xx][0] yCoord = data[xx][1] roi[xCoord][yCoord] = median #print('roi/median: ', roi) # convolution k = (roi*kernel) #print('k: ', k) # store refined mask into output image (removing salt & pepper) #print('y: ', y) #print('pad: ', pad) #print('x: ', x) output[y - pad:y + pad + 1, x - pad:x + pad + 1] = k # rescale the output image output = rescale_intensity(output, in_range=(0, 255)) output = (output * 255).astype("uint8") # return the output image return output # construct kernel mask median = np.ones((7, 7), dtype="float") # run the functions adaptiveOutput = adaptiveMedian(image, median) medianOutput = medianFilter(image2, median) # plot both images plt.figure(figsize=(11,6)) plt.subplot(131),plt.imshow(image, cmap = 'gray') plt.title('Original Image w/ noise added'), plt.xticks([]), plt.yticks([]) plt.subplot(132),plt.imshow(medianOutput, cmap = 'gray') plt.title('Median Filter'), plt.xticks([]), plt.yticks([]) plt.subplot(133),plt.imshow(adaptiveOutput, cmap = 'gray') plt.title('Adaptive Median Filter'), plt.xticks([]), plt.yticks([]) plt.show()
Had to change the main for loop:
yRange = np.arange(pad, iH + pad) xRange = np.arange(pad, iW + pad) # loop over the input image for y in yRange[::6]: for x in xRange[::6]:Also putting the output[...] = k line in the for xx loop, everything seems to work now:
for xx in range(0,Range): xCoord = data[xx][0] yCoord = data[xx][1] roi[xCoord][yCoord] = median #print('roi/median: ', roi) # convolution k = (roi*kernel) #print('k: ', k) # store refined mask into output image (removing salt & pepper) #print('y: ', y) #print('pad: ', pad) #print('x: ', x) output[y - pad:y + pad + 1, x - pad:x + pad + 1] = k