Otsu 掩膜内阈值化
Otsu thresholding inside mask
我正在使用 Python 并尝试对图像进行 Otsu 阈值处理,但仅限于蒙版内部(是的,我有一个图像和一个蒙版图像)。这意味着图像上较少的像素将包含在用于计算大津阈值的直方图中。
我目前正在使用没有蒙版图像的 cv2.threshold
函数,不知道如何做这种工作。
ret, OtsuMat = cv2.threshold(GaborMat, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
由于此函数还合并了掩码外的像素,我认为它会给出不太准确的阈值。
这是图像及其遮罩的示例:
https://drive.google.com/drive/folders/1p8JMhncJs19oOWO9RdkWuEADVGqE-gzQ?usp=sharing
希望有一个 OpenCV 或其他 lib 函数可以轻松地完成它(并且还具有快速计算),但我们将不胜感激。
我尝试使用 skimage 中的 threshold_otsu()
方法和 Numpy 屏蔽数组。我不知道是否有更快的方法 - skimage 通常优化得很好。如果其他人想使用我的示例数据并尝试其他想法,请随意 - 尽管需要支付一次投票的服务费 ;-)
#!/usr/bin/env python3
import cv2
import numpy as np
import numpy.ma as ma
from skimage.filters import threshold_otsu
# Set up some repeatable test data, 4 blocks 100x100 pixels each of random normal np.uint8s centred on 32, 64, 160,192
np.random.seed(42)
a=np.random.normal(size = (100,100), loc = 32,scale=10).astype(np.uint8)
b=np.random.normal(size = (100,100), loc = 64,scale=10).astype(np.uint8)
c=np.random.normal(size = (100,100), loc = 160,scale=10).astype(np.uint8)
d=np.random.normal(size = (100,100), loc = 192,scale=10).astype(np.uint8)
# Stack (concatenate) the 4 squares horizontally across the page
im = np.hstack((a,b,c,d))
# Next line is just for debug
cv2.imwrite('start.png',im)
这给了我们这个:
# Now make a mask revealing only left half of image, centred on 32 and 64
mask=np.zeros((100,400))
mask[:,200:]=1
masked = ma.masked_array(im,mask)
print(threshold_otsu(masked.compressed())) # Prints 47
# Now do same revealing only right half of image, centred on 160 and 192
masked = ma.masked_array(im,1-mask)
print(threshold_otsu(masked.compressed())) # Prints 175
测试数据的直方图是这样的,x-axis是0..255
适应你自己的样本数据,我得到这个:
#!/usr/bin/env python3
import cv2
import numpy as np
import numpy.ma as ma
from skimage.filters import threshold_otsu
# Load images
im = cv2.imread('eye.tif', cv2.IMREAD_UNCHANGED)
mask = cv2.imread('mask.tif', cv2.IMREAD_UNCHANGED)
# Calculate Otsu threshold on entire image
print(threshold_otsu(im)) # prints 130
# Now do same for masked image
masked = ma.masked_array(im,mask>0)
print(threshold_otsu(masked.compressed())). # prints 124
我正在使用 Python 并尝试对图像进行 Otsu 阈值处理,但仅限于蒙版内部(是的,我有一个图像和一个蒙版图像)。这意味着图像上较少的像素将包含在用于计算大津阈值的直方图中。
我目前正在使用没有蒙版图像的 cv2.threshold
函数,不知道如何做这种工作。
ret, OtsuMat = cv2.threshold(GaborMat, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
由于此函数还合并了掩码外的像素,我认为它会给出不太准确的阈值。
这是图像及其遮罩的示例:
https://drive.google.com/drive/folders/1p8JMhncJs19oOWO9RdkWuEADVGqE-gzQ?usp=sharing
希望有一个 OpenCV 或其他 lib 函数可以轻松地完成它(并且还具有快速计算),但我们将不胜感激。
我尝试使用 skimage 中的 threshold_otsu()
方法和 Numpy 屏蔽数组。我不知道是否有更快的方法 - skimage 通常优化得很好。如果其他人想使用我的示例数据并尝试其他想法,请随意 - 尽管需要支付一次投票的服务费 ;-)
#!/usr/bin/env python3
import cv2
import numpy as np
import numpy.ma as ma
from skimage.filters import threshold_otsu
# Set up some repeatable test data, 4 blocks 100x100 pixels each of random normal np.uint8s centred on 32, 64, 160,192
np.random.seed(42)
a=np.random.normal(size = (100,100), loc = 32,scale=10).astype(np.uint8)
b=np.random.normal(size = (100,100), loc = 64,scale=10).astype(np.uint8)
c=np.random.normal(size = (100,100), loc = 160,scale=10).astype(np.uint8)
d=np.random.normal(size = (100,100), loc = 192,scale=10).astype(np.uint8)
# Stack (concatenate) the 4 squares horizontally across the page
im = np.hstack((a,b,c,d))
# Next line is just for debug
cv2.imwrite('start.png',im)
这给了我们这个:
# Now make a mask revealing only left half of image, centred on 32 and 64
mask=np.zeros((100,400))
mask[:,200:]=1
masked = ma.masked_array(im,mask)
print(threshold_otsu(masked.compressed())) # Prints 47
# Now do same revealing only right half of image, centred on 160 and 192
masked = ma.masked_array(im,1-mask)
print(threshold_otsu(masked.compressed())) # Prints 175
测试数据的直方图是这样的,x-axis是0..255
适应你自己的样本数据,我得到这个:
#!/usr/bin/env python3
import cv2
import numpy as np
import numpy.ma as ma
from skimage.filters import threshold_otsu
# Load images
im = cv2.imread('eye.tif', cv2.IMREAD_UNCHANGED)
mask = cv2.imread('mask.tif', cv2.IMREAD_UNCHANGED)
# Calculate Otsu threshold on entire image
print(threshold_otsu(im)) # prints 130
# Now do same for masked image
masked = ma.masked_array(im,mask>0)
print(threshold_otsu(masked.compressed())). # prints 124