I have a remote sensing photo that has bright non continuous vertical streaks or stripes as in the pic below, my question is there a way to remove them using python and opencv or any other ip library?
,
Here is another way, but it requires one to do Hit and Miss morphology on a grayscale image. Python/OpenCV (and Scipy and Mahouts) only allow Hit and Miss on binary images. So I use Imagemagick to do the full processing. (I tried the same in Python/OpenCV, but it failed due to that requirement). If you must use Python, then try similar processing in Python Wand, which uses Imagemagick. Or make a subprocess call from Python to Imagemagick.
Input:

magick remote_sense.jpg \
\( -clone 0 -statistic median 7x1 +write remote_sense_med_7x1.png \) \
\( -clone 0 -scale x1! -scale 1617x1210! +write remote_sense_scaled.png \
-morphology Hit-and-Miss '5x1:0,1,1,1,0' \
-morphology Dilate '3x1:1,1,1' \
-auto-level -threshold 10% +write remote_sense_mask.png \) \
-compose over -composite \
remote_sense_filtered.jpg
Median Filtered Image:

Image averaged to one row and scale back to full size:

Mask from Hit and Miss:

Filtered Result:

1 approach might be to apply an low pass filter on averaged columns to find the "bands" and remove them.
The implementation below use np.fft and np.ifft to remove frequencies. Other filters could be used here.
Warning - this sharp frequency cutoff leaves some "ringing" on the edges of the image (which can be somewhat removed by adding the average slope to it).
import cv2
img = cv2.imread("iamHP.jpg")
# Plot image
import matplotlib.pyplot as plt
plt.rcParams["figure.dpi"] = 200 # for bigger plot
plt.imshow(img)
plt.show()
import numpy as np
img_copy = np.copy(img)
mean_vals = np.mean(img, axis = 0)
def custom_filter_here(original):
avg_slope = np.linspace(original[-1], original[0], original.shape[0])
fft_data = np.fft.fft(original + avg_slope)
fft_data[40:-40] = 0
reconstructed = np.abs(np.fft.ifft(fft_data))
return reconstructed - avg_slope
#For each channel
for i in range(mean_vals.shape[1]):
#Stripes vs filtered
original = mean_vals[:, i]
reconstructed = custom_filter_here(original)
#Plot difference
plt.plot(original)
plt.plot(reconstructed)
plt.show()
#Fix image
for j, val in enumerate(reconstructed - original):
img[:,j,i] = (img[:,j,i] + int(val)).astype(np.uint8)
#See the output
plt.imshow(img)
plt.show()
#See the change
change = img_copy.astype(np.float64) - img.astype(np.float64)
change -= np.min(change)
change /= np.max(change)
plt.imshow(change)
plt.show()
#save the image
cv2.imwrite("test.jpg", img)

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With