问题
Testing image
I write a Python script that manually do a Erosion Morphological Operation to an image using the attached test image, but when I display both the original and altered image, this last one still looks the same even thought is it supposed to be eroded.
I have 3 functions, my Main function, a RGB to Gray Conversion function and the Erosion function.
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()
What my code does is take the test image, convert it to Gray Scale (just one color channel) and pass to the Erode function. I create a structuring element to work with which is a matrix that will work as my kernel during the process. I crop a region of the gray scale image and convert it to a matrix of the same size of my structuring element (kernel), then, I "overpose" the two matrix to see if any pixel in a specific coordinate of one matrix have the same value in the same coordinate of the second matrix. I create a copy of the gray scale image called ero which is the one I will modified.
There are 3 cases.
1) If all black pixels match, it fits and do nothing
2) If one or more (but not all) black pixels match it fits and it should change the color of the center pixel of ero to black
3) If no pixel match it should do nothing.
I use the first 2 for cycles to crop different regions of the image to pass throught the whole area, the next two for loops are use to iterate over each pixel of the crop image and the kernel and check if the pixels match. **I think the error is in the line marked as
##PROBABLE ERROR IN HERE##
because is the one that specifies to change the color of the central pixel.** (Which is not changing)
If I run the code both images (gray scale original and ero image) look just the same. Any thoughts on what the error could be?
回答1:
Because w
never changes, a
and b
are also always the same. Hence, when you write to the output with ero[a][b] = 0
, you are always setting the same pixel to 0. Instead, set the pixel at the center of your window:
ero[i+a][j+b] = 0
Additionally, ero = im
causes both variables to reference the same array, modifying the one will modify the other. Create a copy as Mark suggests in a comment:
ero = np.copy(im)
The code might have more issues, I have not tried running it. It certainly can use some vectorization: the loop over x
and y
can be replace with two vectorized NumPy operations:
blacks = np.coount_nonzero(img == 0)
matches = np.coount_nonzero((img == 0) & (se == 0))
However, assuming both the image and the structuring element only have values of 0 and 255, the erosion operation should be simply written as
ero[i+a][j+b] = np.all(img[se==255]) * 255
That is, the output is set only if all pixels where the SE hits are set. The complication here comes from using numeric arrays with values 0 and 255 instead of logical arrays, which would simplify the expression even further.
The dilation would replace all
with any
.
来源:https://stackoverflow.com/questions/63098284/image-erosion-manual-implementation-not-doing-anything-python