Paper name: parameter free fast pixelwise non local means denoising
Paper Download: IPOL Journal · Parameter-Free Fast Pixelwise Non-Local Means Denoisinghttps://www.ipol.im/pub/art/2014/120/
Previously, I shared an article on NLM denoising (NLM_B) at the block level. This article is based on NLM denoising(NLM_P) at the pixel level. There are mainly two NLMS_ PA and NLM_ P. The difference is that when calculating the distance between blocks, NLM_Pa uses Gaussian Euclidean norm, while NLM_ P uses Euclidean norm. Of course, and NLM_ B the difference is that when calculating the weight, there is no reduction of 2*sigma^2. It should be that there is no reduction in the original paper, which is reduced in non local means denoising IPOL Journal · Non-Local Means Denoising.
Next, the calculation pseudo code of the basic algorithm is introduced, and the calculation complexity is analyzed to pave the way for the later optimization.
Several optimization methods are introduced for NLM_P. Due to its particularity, the integral graph can be used for optimization, and the complexity can be reduced. The optimization based on Fourier transform is also introduced, but when the image is large, the computational complexity is very high. Finally, the key method SIL of the article can reduce the computational complexity. The NLM series functions in OpenCV (fastnlmeans denoising colored) should refer to this method.
Because the parameters are related to the noise intensity, this paper analyzes how to set the optimal parameters. By constructing two data sets and taking PSNR as the standard, the optimal parameters are obtained.
Finally, NLM is analyzed and compared_ P and NLM_ From the PSNR data, NLM is basically better than NLM-P/NLM-Pa, but the subjective effect is quite good (I feel a little rogue).
The paper discloses the C code( IPOL Journal · Parameter-Free Fast Pixelwise Non-Local Means Denoising ), there is only the SIL method, which has not been studied carefully. If you can actually use the algorithm, take a closer look. If you just look at the effect, you can call the functions in OpenCV.
In addition, for the basic algorithm flow, the single channel is simply written in Python code (the step of calculating the weight should be calculated as a table in advance, and then look up the table). It can be used as a reference. According to this, which can be extended to color images, the python code will be very slow. The code refers to this blog post Nonlocal mean filtering-a non local algorithm for image denoising_ Nick blog CSDN blog 1 Introduction non local means, as the name suggests, is a non local average algorithm. What is the local average filtering algorithm? That is the method of smoothing the mean value around a target pixel, so nonlocal mean filtering means that it uses all pixels in the image, which are weighted and averaged according to a certain similarity. The filtered image has high definition and does not lose details. 2. Principle the algorithm uses the redundant information commonly existing in natural images to remove noise. Different from bilinear filtering and median filtering, which use the local information of the image to filter, it uses the whole image for denoising. That is to find similar regions in the image in the unit of image block, and then weighted average these regions to better filter out the Gaussian noise in the image. two point one https://niecongchong.blog.csdn.net/article/details/111304042
def GaussianKernel(d, sigma): # Generate array ax = np.arange(-d // 2 + 1., d // 2 + 1.) # Generate 2D matrices by duplicating ax along two axes xx, yy = np.meshgrid(ax, ax) # kernel will be the gaussian over the 2D arrays kernel = np.exp(-(xx**2 + yy**2) / (2. * sigma**2)) # Normalise the kernel final = kernel / kernel.sum() return final def onLocalMeansGray_NLMP(image, h=10, templateWindowSize=7, searchWindow=21): height, width = image.shape[0], image.shape[1] patchWin = int(templateWindowSize / 2) searchWind = int(searchWindow / 2) # Padding the image padLength = patchWin + searchWind img = cv2.copyMakeBorder(image, padLength, padLength, padLength, padLength, cv2.BORDER_CONSTANT, value=255) # output image outImage = np.zeros((height, width), dtype='float') # generate gaussian kernel matrix of 7*7 kernel = GaussianKernel(templateWindowSize, 1) # Run the non-local means for each pixel for j in range(height): for i in range(width): padj = j + padLength padi = i + padLength centerPatch = img[padj - patchWin: padj + patchWin + 1, padi - patchWin: padi + patchWin + 1] sumPixel = 0 sumWeight = 0 # Apply Gaussian weighted square distance between patches of 7*7 in a window of 21*21 for r in range(padj - searchWind, padj + searchWind): for c in range(padi - searchWind, padi + searchWind): otherPatch = img[r - patchWin: r + patchWin + 1, c - patchWin: c + patchWin + 1] diff = centerPatch - otherPatch distance_2 = np.multiply(diff, diff) pixelWeight = np.sum(np.multiply(kernel, distance_2)) pixelWeight = np.exp(pixelWeight / (h**2)) sumWeight = sumWeight + pixelWeight sumPixel = sumPixel + pixelWeight * img[r, c] outImage[j, i] = sumPixel / sumWeight outImage = np.clip(outImage, 0, 255) outImage = outImage.astype(np.uint8) return outImage