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

Нужно улучшить алгоритм или преобработку изображения, чтобы работало даже с большим шумом. Шум такой, что: Каждое изображение зашумлено с вероятностью P (от 0 до 0.9), то есть значение каждого), то есть значение каждого пикселя заменяется на случайное целое, равномерно распределенное на отрезке [0; 255].