class Solver(object):

    def __init__(self):
        self.filter_size = 7
        self.threshold = 0.1
        self.dist = 90
        self.max_corners = 3

    def get_window_weight(self):
        gausskernel=np.zeros((self.filter_size,self.filter_size),np.float32)
        offset = self.filter_size // 2
        for i in range (self.filter_size):
            for j in range (self.filter_size):
                norm=np.square(i-offset) + np.square(j-offset)
                gausskernel[i, j] = np.exp(-norm / (2 * np.square(1)))
            sum = np.sum (gausskernel)
            kernel = gausskernel / sum
        return kernel

    def find_corners(self, image):
        Ix = cv2.Scharr(image, cv2.CV_64F, 1, 0)
        Iy = cv2.Scharr(image, cv2.CV_64F, 0, 1)
        #Iy, Ix = np.gradient(image)
        Ixx = np.square(Ix)
        Iyy = np.square(Iy)
        Ixy = Ix * Iy#

        height = image.shape[0]
        width = image.shape[1]
        offset = self.filter_size // 2
        weight = self.get_window_weight()
        corners = []
        for y in range(offset, height - offset):
            for x in range(offset, width - offset):
                fIxx = Ixx[y - offset:y + offset + 1, x - offset:x + offset + 1]
                fIyy = Iyy[y - offset:y + offset + 1, x - offset:x + offset + 1]
                fIxy = Ixy[y - offset:y + offset + 1, x - offset:x + offset + 1]#

                Sxx = (fIxx * weight).sum()
                Syy = (fIyy * weight).sum()
                Sxy = (fIxy * weight).sum()#

                A = np.array([[Sxx, Sxy],
                              [Sxy, Syy]])

                R = min(np.linalg.eigh(A)[0])


                if R > 0:
                    corners.append([x, y, R])

        return np.array(corners)


    def filtered_corners(self, corners):
        corners = corners[corners[:, 2].argsort()]
        corners = np.flip(corners, axis = 0)
        thresh = corners[0,2] * self.threshold
        corners = corners[corners[:,2] >= thresh]

        distance_filtered_corners = [corners[0]]
        for x in corners:
            bigger = True
            for y in distance_filtered_corners:
                if np.linalg.norm(x[:2] - np.array(y[:2])) <= self.dist:
                    bigger = False
                    break
            if bigger:
                distance_filtered_corners.append(x)

        if len(distance_filtered_corners) > self.max_corners:
            return distance_filtered_corners[:self.max_corners]

        return distance_filtered_corners


    def image_pre_processing(self, img):
        img = cv2.GaussianBlur(img, (25, 25), 0)
        #@@@
        ImageService.show_image(img)
        return img


    def solve(self, image_gray: np.ndarray) -> list:
        image = self.image_pre_processing(image_gray)
        corners = self.find_corners(image)
        filtered_corners_list = self.filtered_corners(corners)
        keypoints = list(np.array(filtered_corners_list)[:, [0,1]].astype(int))
        return keypoints



image = cv2.imread("0.5/02.pgm", cv2.COLOR_BGR2GRAY)

#@@@
import pywt



def wavelet_filtering(image_gray):
    # Применение вейвлет-преобразования
    coeffs = pywt.dwt2(image_gray, "haar")

    # Изменение амплитуд коэффициентов вейвлетов для фильтрации
    coeffs = list(coeffs)
    for i in range(0, len(coeffs)):
        coeffs[i] = pywt.threshold(coeffs[i], np.std(coeffs[i]), mode="soft")

    # Инвертирование вейвлет-преобразования
    image_filtered = pywt.idwt2(coeffs, "haar")

    return image_filtered


def median_filter(image_gray, filter_size):
    filtered_image = np.zeros_like(image_gray)
    
    offset = filter_size // 2
    
    height, width = image_gray.shape
    for y in range(offset, height - offset):
        for x in range(offset, width - offset):
            window = image_gray[y - offset:y + offset + 1, x - offset:x + offset + 1]
            median_value = np.median(window)
            filtered_image[y, x] = median_value
    
    return filtered_image


# image_filtered = wavelet_filtering(image)
# image_filtered = median_filter(image, filter_size=2)


print("image filtered")
ImageService.show_image(image)

cv2.waitKey(0)

solver = Solver()
corners = solver.solve(image)


# vizualization
x = np.array(corners)[:,0].astype(int)
y = np.array(corners)[:,1].astype(int)

image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)

for i in range(len(x)):
    cv2.circle(image, (x[i],y[i]), 5, [255, 0, 0], 2)

plt.imshow(image)


Код не устойчив к шуму, исправь так, чтобы корректно работал даже при шуме