使用openCV2去除水平条纹 [英] Removal of horizontal stripes using openCV2
问题描述
我是openCV的新手,我想知道是否有办法消除此图像下半部分的周期性条纹.
I am new to openCV and I was wondering if there is a way to remove the periodic stripes in the lower half of this image.
I looked at this post but couldn't quite understand what was going on: Removing periodic noise from an image using the Fourier Transform
推荐答案
以下是如何使用傅立叶变换和使用Python/OpenCV/Numpy进行陷波过滤处理来减轻(减少,但不能完全消除)线条的方法.由于输入中的水平线非常接近,因此在傅立叶变换频谱中将存在水平的线性结构.所以我所做的是:
Here is how to mitigate (reduce, but not totally eliminate) the lines using Fourier Transform and notch filtering processing with Python/OpenCV/Numpy. Since the horizontal lines in the input are very close, there will be horizontal linear structures spaced far apart in the Fourier Transform spectrum. So what I did was:
- 阅读输入内容
- 以2的幂的均值填充(以减轻填充不连续引起的振铃)
- 进行DFT
- 根据幅度计算光谱图像
- 阈值图像并在中心绘制一条黑色水平线以消除明亮的DC分量
- 找到亮点(线条)的显示位置.
- 获取亮点的坐标并在阈值图像上绘制白色水平线以形成蒙版
- 将遮罩应用于量级图像
- 进行IDFT
- 重新裁切大小并归一化为与原始图像相同的动态范围
- Read the input
- Pad with the mean value to powers of 2 size (to try to mitigate any ringing from the discontinuity with the padding)
- Do the DFT
- Compute the spectrum image from the magnitude
- Threshold the image and draw a black horizontal line through the center to blank out the bright DC component
- Find where the bright spots (lines) show.
- Get the coordinates of the bright spots and draw white horizontal lines on the thresholded image to form a mask
- Apply the mask to the magnitude image
- Do the IDFT
- Crop back to the size and normalize to the same dynamic range as the original image
输入:
import numpy as np
import cv2
import math
# read input as grayscale
img = cv2.imread('pattern_lines.png', 0)
hh, ww = img.shape
# get min and max and mean values of img
img_min = np.amin(img)
img_max = np.amax(img)
img_mean = int(np.mean(img))
# pad the image to dimension a power of 2
hhh = math.ceil(math.log2(hh))
hhh = int(math.pow(2,hhh))
www = math.ceil(math.log2(ww))
www = int(math.pow(2,www))
imgp = np.full((hhh,www), img_mean, dtype=np.uint8)
imgp[0:hh, 0:ww] = img
# convert image to floats and do dft saving as complex output
dft = cv2.dft(np.float32(imgp), flags = cv2.DFT_COMPLEX_OUTPUT)
# apply shift of origin from upper left corner to center of image
dft_shift = np.fft.fftshift(dft)
# extract magnitude and phase images
mag, phase = cv2.cartToPolar(dft_shift[:,:,0], dft_shift[:,:,1])
# get spectrum
spec = np.log(mag) / 20
min, max = np.amin(spec, (0,1)), np.amax(spec, (0,1))
# threshold the spectrum to find bright spots
thresh = (255*spec).astype(np.uint8)
thresh = cv2.threshold(thresh, 155, 255, cv2.THRESH_BINARY)[1]
# cover the center rows of thresh with black
yc = hhh // 2
cv2.line(thresh, (0,yc), (www-1,yc), 0, 5)
# get the y coordinates of the bright spots
points = np.column_stack(np.nonzero(thresh))
print(points)
# create mask from spectrum drawing horizontal lines at bright spots
mask = thresh.copy()
for p in points:
y = p[0]
cv2.line(mask, (0,y), (www-1,y), 255, 5)
# apply mask to magnitude such that magnitude is made black where mask is white
mag[mask!=0] = 0
# convert new magnitude and old phase into cartesian real and imaginary components
real, imag = cv2.polarToCart(mag, phase)
# combine cartesian components into one complex image
back = cv2.merge([real, imag])
# shift origin from center to upper left corner
back_ishift = np.fft.ifftshift(back)
# do idft saving as complex output
img_back = cv2.idft(back_ishift)
# combine complex components into original image again
img_back = cv2.magnitude(img_back[:,:,0], img_back[:,:,1])
# crop to original size
img_back = img_back[0:hh, 0:ww]
# re-normalize to 8-bits in range of original
min, max = np.amin(img_back, (0,1)), np.amax(img_back, (0,1))
notched = cv2.normalize(img_back, None, alpha=img_min, beta=img_max, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
cv2.imshow("ORIGINAL", img)
cv2.imshow("PADDED", imgp)
cv2.imshow("MAG", mag)
cv2.imshow("PHASE", phase)
cv2.imshow("SPECTRUM", spec)
cv2.imshow("THRESH", thresh)
cv2.imshow("MASK", mask)
cv2.imshow("NOTCHED", notched)
cv2.waitKey(0)
cv2.destroyAllWindows()
# write result to disk
cv2.imwrite("pattern_lines_spectrum.png", (255*spec).clip(0,255).astype(np.uint8))
cv2.imwrite("pattern_lines_thresh.png", thresh)
cv2.imwrite("pattern_lines_mask.png", mask)
cv2.imwrite("pattern_lines_notched.png", notched)
频谱(注意中间的亮点在y = 64和192处):
Spectrum (note the bright spots in the middle at y=64 and 192):
阈值图像:
亮点位置:
[[ 0 1023]
[ 0 1024]
[ 0 1025]
[ 1 1024]
[ 64 1024]
[ 65 1024]
[ 191 1024]
[ 192 1024]
[ 255 1024]]
遮罩:
结果:
这篇关于使用openCV2去除水平条纹的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!