Отсу порог внутри маски - PullRequest
1 голос
/ 11 июня 2019

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

В настоящее время я использую функцию 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, чтобы сделать это легко (а также с быстрыми вычислениями), но любая помощь будет признательна.

1 Ответ

2 голосов
/ 11 июня 2019

Я попробовал это, используя метод threshold_otsu() из skimage и массив Numpy.Я не знаю, есть ли более быстрые способы - лыжный маг обычно довольно хорошо оптимизирован.Если кто-то еще захочет взять мои образцы данных и попробовать другие идеи на них, пожалуйста, не стесняйтесь - хотя с одного сбора взимается плата за обслуживание; -)

#!/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)

Это дает нам следующее:

enter image description here

# 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 равна 0..255

enter image description here


Адаптируясь к вашим собственным образцам данных, я получаю это:

#!/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
...