OpenCV: есть ли альтернатива cv2.inRange с использованием радиуса? - PullRequest
0 голосов
/ 09 октября 2018

Я знаком с функцией inRange OpenCV для создания маски.Допустим, я хочу получить маску пикселей в цветовом диапазоне «вокруг» определенного цвета, я могу сделать это:

color = np.array([240, 60, 70])
max_dist = 50
img = cv2.inRange(img, [color] - max_dist, [color] + max_dist)

Но это маскирует все цвета BGR в «кубе» вокруг центрального цвета,Я ищу альтернативу, используя «сферу» вокруг центрального цвета в пространстве BGR, то есть евклидово расстояние.Любые идеи?

Я могу, конечно, пройтись по изображению, вычислить расстояния, используя scipy.spatial.distance.cdist, а затем пройти по всем пикселям по одному и либо включить, либо исключить их из маски.Тем не менее, это очень медленно в питоне ...

Спасибо!

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Наконец-то получил рабочий ответ.Если быть точным, я не хочу ограничивать себя одним цветом, а разрешить несколько цветов.Я использую встроенную функцию cdist + постобработку, предложенную выше dobkind для преобразования расстояний в маску.Это работает примерно на 7% быстрее, чем предыдущий подход.

max_dist = 10
colors = np.array([[250,40,60],[245,245,245]])
dist = scipy.spatial.distance.cdist(colors, img.reshape(-1, 3), 'euclidean')
mask = np.any(dist <= max_dist, axis=0).reshape(img.shape[0], img.shape[1])
img = np.repeat(mask[..., None], 3, axis=2) * img
0 голосов
/ 09 октября 2018

Создать маску, которая указывает пиксели, евклидово расстояние которых меньше, чем max_dist:

R = img[:, :, 0].astype(np.float32)
G = img[:, :, 1].astype(np.float32)
B = img[:, :, 2].astype(np.float32)

sq_dist = (R - color[0]) ** 2 + (G - color[1]) ** 2 + (B - color[2]) ** 2

mask = sq_dist < (max_dist ** 2)

masked_img = np.repeat(mask[..., None], 3, axis=2) * img
...