为什么 opencv 'cv2.morphologyEx' 操作在迭代过程中在一个方向上移动图像?

Why opencv 'cv2.morphologyEx' operations shift images in one direction during iterations?

我目前正在使用 OpenCV 中的 "morphologyEx" 操作来消除图像中的一些噪声。它运行成功,但由于某些奇怪的原因,roi 在迭代过程中一直向南移动。 原图为:

带有比例尺的图像:

我是运行的python脚本是

test_image = r"C:/test/test.bmp"
image = cv2.imread(test_image,cv2.COLOR_BAYER_BG2RGB)
blurred = cv2.medianBlur(image, 3) 
ret,binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)
img_adj = cv2.morphologyEx(blurred, cv2.MORPH_OPEN,(3,11),iterations=25)
#imshow(binary)
imshow(img_adj)

但迭代后如下:

图像 roi 已向南移动,这与迭代次数成正比。 我怎样才能防止移位?

主要问题是传递给 cv2.morphologyEx(3,11) 参数。

根据morphologyEx的文档,内核是一个结构元素,而不是内核的大小。

传递 (3,11) 可能就像传递 np.array([1, 1])(或者只是未定义的行为)。

正确的语法是向 3x11 NumPy 传递一个数组(和 uint8 类型):

img_adj = cv2.morphologyEx(blurred, cv2.MORPH_OPEN, np.ones((3, 11), np.uint8), iterations=25)

使用具有 25 次迭代的大内核太多了,所以我将其减少为 3x5 和 5 次迭代。

以下代码示例显示图像未移动:

import cv2
import numpy as np

test_image = "test.bmp"
#image = cv2.imread(test_image, cv2.COLOR_BAYER_BG2RGB) # cv2.COLOR_BAYER_BG2RGB is not in place
image = cv2.imread(test_image, cv2.IMREAD_GRAYSCALE)  # Read image as grayscale
blurred = cv2.medianBlur(image, 3) 
ret, binary = cv2.threshold(blurred, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)
#img_adj = cv2.morphologyEx(blurred, cv2.MORPH_OPEN, (3, 11), iterations=25)
img_adj = cv2.morphologyEx(blurred, cv2.MORPH_OPEN, np.ones((3, 5), np.uint8), iterations=5)

montage_img = np.dstack((255-image, 0*image, 255-img_adj)) # Place image in the blue channel and img_adj in the red channel

# Show original and output images using OpenCV imshow method (instead of using matplotlib)
cv2.imshow('image', image)
cv2.imshow('img_adj', img_adj)
cv2.imshow('montage_img', montage_img)
cv2.waitKey()
cv2.destroyAllWindows()

image:

img_adj:

montage_img:


更好的解决方案是找到最大的连通分量(不是背景):

import cv2
import numpy as np

test_image = "test.bmp"
image = cv2.imread(test_image, cv2.IMREAD_GRAYSCALE)  # Read image as grayscale
ret, binary = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)

nb_components, output, stats, centroids = cv2.connectedComponentsWithStats(binary, 8)  # Finding connected components

# Find the largest non background component.
# Note: range() starts from 1 since 0 is the background label.
max_label, max_size = max([(i, stats[i, cv2.CC_STAT_AREA]) for i in range(1, nb_components)], key=lambda x: x[1])

res = np.zeros_like(binary) + 255
res[output == max_label] = 0

cv2.imshow('res', res)
cv2.waitKey()
cv2.destroyAllWindows()

结果: