Background:I want to get the width of the hot steel by manipulating a row of pixel values ,such as the green line in the picture.This pixel value change has been processed to be between 0 and 255.
But there will be noise interference on the surface of hot steel. The correct hot steel boundary cannot be found based on the pixel change curve. The red box in the image below is the noise interference, and the real boundary is where the red arrow indicates.What better way to get rid of the noise?
The method I use:
- lowpass it a bit to supress noise
- gradient
- remove some noise according to the peaks and troughs of the gradient curve
- maximum and minimum are rising and falling edge
The problem:The method I use does improve the effect and remove some of the noise, but there are still some problems. In the image below, it removes the crest in the green box, thus finding the wrong left boundary (red vertical line).
The gradient map after removing noise:
The code:
import numpy as np
from scipy.signal import find_peaks
from scipy.ndimage import gaussian_filter1d
import matplotlib.pyplot as plt
def SmoothGra(peaks, valleys, gradient):
threshold_distance = 65 #Peak and trough distance threshold
filtered_peaks = []
filtered_valleys = []
filtered_pairs = []
gra = gradient.copy()
for k,peak_idx in enumerate(peaks):
for valley_idx in valleys:
if abs(peak_idx - valley_idx) <= threshold_distance and abs(
gra[peak_idx] + gra[valley_idx]) < 2 :
filtered_pairs.append((peak_idx, valley_idx))
break
else:
filtered_peaks.append(peak_idx)
for valley_idx in valleys:
for peak_idx in peaks:
if abs(valley_idx - peak_idx) <= threshold_distance and abs(
gra[peak_idx] + gra[valley_idx]) < 2:
break
else:
filtered_valleys.append(valley_idx)
for peak_idx, valley_idx in filtered_pairs:
if peak_idx < valley_idx:
gra[peak_idx - 20:valley_idx + 20] = 0
else:
gra[valley_idx - 20:peak_idx + 20] = 0
return filtered_peaks, filtered_valleys, gra
data=np.load('data.npy') #load data
lowpassed = gaussian_filter1d(data, sigma=10.0)
gradient = np.gradient(lowpassed) #find gradient
#Look for peaks and troughs
peaks, _ = find_peaks(gradient, height=1.5, prominence=1.5, rel_height=0.5)
valleys, _ = find_peaks(-gradient, height=1.5, prominence=1.5, rel_height=0.5)
#The noise is removed according to the position and difference of the peaks and troughs
filtered_peaks, filtered_valleys, gra = SmoothGra(peaks, valleys, gradient)
rising = np.argmax(gra)
falling = np.argmin(gra)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 8))
ax1.plot(range(len(data)), data, color='b')
ax1.set_xlabel('Pixel value')
ax1.set_ylabel('Gray value')
ax1.axvline(x=rising,color='r',linestyle='-')
ax1.axvline(x=falling,color='r',linestyle='-')
ax1.grid(True)
ax2.plot(range(len(gra)), gra, color='b')
ax2.set_xlabel('Pixel value')
ax2.set_ylabel('Gray value')
ax2.grid(True)
for i in filtered_peaks:
ax2.text(i, gra[i], '*', color='r', fontsize=12, verticalalignment='bottom', horizontalalignment='center')
for i in filtered_valleys:
ax2.text(i, gra[i], '*', color='y', fontsize=12, verticalalignment='bottom', horizontalalignment='center')
plt.tight_layout()
plt.show()
The data: can be found here.
Additon:Partial code reference links. Second, I don't want to use opencv, I want to know how my de-noising part function SmoothGra can more accurately remove noise.



