2

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.

enter image description here

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?

enter image description here enter image description here

The method I use:

  1. lowpass it a bit to supress noise
  2. gradient
  3. remove some noise according to the peaks and troughs of the gradient curve
  4. 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).

enter image description here

The gradient map after removing noise:enter image description here

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.

9
  • 1
    the source of the picture is a previous question with answers: stackoverflow.com/questions/73606916/… Commented Apr 2, 2024 at 9:05
  • 1
    this question (how to suppress noise with lowpass) was already answered by answers given on that previous question (different author of course): stackoverflow.com/questions/73606916/… -- parts of this question ("maximum and minimum are rising and falling edge") are copied verbatim from my previous answer -- the upvotes probably found the subject interesting but didn't know the context. you should be upvoting the previous question instead of this one. Commented Apr 2, 2024 at 9:13
  • It's not consistent. The previous problem was using opencv to process images, and I only wanted to use one row of pixel values. I have adopted some of your methods, but the essence of what I want to ask is filtering noise. Commented Apr 2, 2024 at 9:22
  • i.e., it remains to understand your function and figure out what's wrong with it? then you need to adjust the title and the body of the post. feel free to give brief context but focus on your code and the data (that npy file should be the 1D data you want to work on (if that is what you want to work on), not the entire picture). Commented Apr 2, 2024 at 9:59
  • 1
    I don’t know what your gradient smoothing function exactly attempts to do. But you are much better off removing noise in the original 2D image, where you have more information. For example apply that Gaussian filter in 2D before extracting the single line. There are also many non-linear edge-preserving smoothing filters you could use, which one to use depends on the type of noise. Commented Apr 2, 2024 at 13:47

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.