Ручная реализация Image Erosion ничего не делает Python

Тестирование изображения

Я пишу скрипт Python, который вручную выполняет морфологическую операцию эрозии с изображением, используя прикрепленное тестовое изображение, но когда я отображаю исходное и измененное изображение, последнее все равно выглядит одинаково, даже если подумать. должно быть разрушено.

У меня есть 3 функции: моя основная функция, функция преобразования RGB в серый и функция эрозии.

import cv2
import math
import numpy as np
from PIL import Image, ImageFilter

def main():
    #Read image
    img = cv2.imread('pattern04.bmp')
    #Convert it to gray scale (One color channel)
    imgg = gray(img)
    #Manually create my structuring element (kernel)
    se = [[0,1,0],
          [1,1,1],
          [0,1,0]]
    #Call morphological operation function
    erode(imgg,se)


def erode(im,se):
    rows,columns = im.shape[0], im.shape[1]
    #Initialize counters (Just to keep track)
    fit = 0
    hit = 0
    miss = 0

    #Create a copy of the image to modified it´s pixel values
    ero = im
    #Specify kernel size (w*w)
    w = 3

    #
    for i in range(rows-w-1):
        for j in range(columns-w-1):
            #Get a region (crop) of the image equal to kernel size
            crop = im[i:w+i,j:w+j]
            #Convert region of image to an array
            img = np.array(crop)

            #Get center
            a = math.floor(w/2)
            b = math.floor(w/2)
            
            #Initialize counters 
            matches = 0
            blacks = 0

            #Count number of black pixels (0) and value matches between the two matrix
            for x in range(w):
                for y in range(w):
                    #Count number of black pixels (0)
                    if(img[x][y] == 0):
                        blacks = blacks+1
                        #Count number of matching pixel values between the two matrix   
                        if (img[x][y] == se[x][y]):         
                            matches = matches+1

            #Test if structuring element fit crop image pixels
            #If fit it does nothing because center pixel is already black
            if(matches > 0):
                if(matches == blacks):
                    #Touch
                    fit = fit + 1
                    pass
                #Test if structuring element hit crop image pixels
                #If hit change ero center pixel to black
                elif(matches < blacks):
                    #Hit
                    hit = hit+1
                    ##PROBABLE ERROR IN HERE##
                    ero[a][b] = 0
            #If no pixel match just pass
            else:
                #Miss
                miss=miss+1
                pass

    #Print the number of fits, hits, and misses
    print(str(fit) + '\n' + str(hit) + '\n' + str(miss))

    #Show original gray image and eroded image
    cv2.imshow('Original', im)
    cv2.imshow('Erosion', ero)
    cv2.waitKey(0)


#Function to convert RGB image (3 color channels) to Gray scale (1 color channel)
def gray(img):
    channel = img.shape[2]
    if (channel > 1):
        g_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        return(g_img)
    else:
        return(img)

if __name__ == "__main__":
    main()

Что делает мой код, так это берет тестовое изображение, преобразует его в шкалу серого (всего один цветовой канал) и передает в функцию Erode. Я создаю структурирующий элемент для работы с матрицей, которая будет работать как ядро ​​во время процесса. Я обрезаю область изображения в градациях серого и преобразовываю ее в матрицу того же размера, что и мой структурирующий элемент (ядро), затем я накладываю две матрицы друг на друга, чтобы увидеть, имеет ли какой-либо пиксель в определенной координате одной матрицы то же значение в той же координате второй матрицы. Я создаю копию изображения в градациях серого с именем ero, которое я буду изменять.

Три случая.

1) Если все черные пиксели совпадают, он подходит и ничего не делает

2) Если один или несколько (но не все) черных пикселей совпадают, он подходит, и он должен изменить цвет центрального пикселя ero на черный

3) Если ни один пиксель не соответствует, ничего не происходит.

Я использую первые 2 цикла for, чтобы обрезать разные области изображения, чтобы пройти через всю область, следующие два цикла for используются для перебора каждого пикселя изображения обрезки и ядра и проверки совпадения пикселей. ** Я думаю, что ошибка в строке, отмеченной как

##ЗДЕСЬ ВОЗМОЖНА ОШИБКА##

потому что это тот, который указывает на изменение цвета центрального пикселя. ** (который не меняется)

Если я запускаю код, оба изображения (оригинал в оттенках серого и эро-изображение) выглядят одинаково. Есть мысли в чем может быть ошибка?


person Charles    schedule 26.07.2020    source источник
comment
Попробуйте создать свою копию с помощью ero = np.copy(im)   -  person Mark Setchell    schedule 26.07.2020


Ответы (1)


Поскольку w никогда не меняется, a и b также всегда одинаковы. Следовательно, когда вы записываете вывод с помощью ero[a][b] = 0, вы всегда устанавливаете один и тот же пиксель в 0. Вместо этого установите пиксель в центре вашего окна:

ero[i+a][j+b] = 0

Кроме того, ero = im заставляет обе переменные ссылаться на один и тот же массив, изменение одной из которых изменит другую. Создайте копию , как предлагает Марк в комментарии:

ero = np.copy(im)

Код может иметь больше проблем, я не пробовал его запускать. Он, безусловно, может использовать некоторую векторизацию: цикл по x и y можно заменить двумя векторизованными операциями NumPy:

blacks = np.coount_nonzero(img == 0)
matches = np.coount_nonzero((img == 0) & (se == 0))

Однако, предполагая, что и изображение, и элемент структурирования имеют только значения 0 и 255, операцию эрозии следует просто записать как

ero[i+a][j+b] = np.all(img[se==255]) * 255

То есть вывод устанавливается только в том случае, если установлены все пиксели, в которые попали SE. Сложность здесь возникает из-за использования числовых массивов со значениями 0 и 255 вместо логических массивов, что еще больше упростило бы выражение.

Расширение заменит all на any.

person Cris Luengo    schedule 26.07.2020
comment
Но если я заменю цикл на x и y, чтобы заменить их векторизованными операциями, как я буду определять свои значения x и y? И 'ero[i+a][j+b] = np.all(img[se==255]) * 255' должен идти внутри оператора if 'if(matches ‹ blacks)'? - person Charles; 28.07.2020
comment
@Charles: извините, я забыл удалить там x и y. Фиксированный. Другой оператор предназначен для всех пикселей, нет необходимости в ifs. Также не нужно инициализировать выходное изображение копированием входного, можно просто создать неинициализированное изображение нужного размера. Это утверждение говорит о том, что «выход устанавливается только в том случае, если все пиксели, покрытые SE, являются пикселями переднего плана». - person Cris Luengo; 28.07.2020