Рисование ограничительной рамки на больших изображениях
У меня есть большое двоичное изображение (4k x 7k pix), из которого я хочу извлечь всю желтую часть в виде одного прямоугольника. Я пробовал бинарную эрозию, чтобы выровнять объекты внутри желтой области. Тогда я использовал bbox
метод skimage.regionprops
но он не работает достаточно быстро для большого изображения с одним большим bbox. Есть ли у вас предложения?
2 ответа
Поскольку предоставленное вами изображение включает отвлекающие оси, и оно имеет неправильный и слишком маленький цвет, я создал максимально реалистичную версию с ImageMagick в терминале, например:
convert bbox.png -alpha off -crop 120x215+40+13 -colorspace gray -normalize -threshold 50% -scale 4200x7200\! bbox.png
Полноразмерная версия - 4200x7200.
Я тогда написал numpy
версия на основе bbox
следующее
#!/usr/local/bin/python3
import numpy as np
from PIL import Image
def bbox(image):
"""Find bounding box of image"""
# Project all columns into row same width as image
proj=np.any(image,axis=0)
# Find first non-zero value from Left
L=np.argmax(proj)
# And right
R=image.shape[1]-np.argmax(np.flipud(proj))-1
# Project all rows into column same height as image
proj=np.any(image,axis=1)
# Find first non-zero value from Top
T=np.argmax(proj)
# And Bottom
B=image.shape[0]-np.argmax(np.flipud(proj))-1
return T,L,B,R
image=np.array(Image.open("a.png").convert("L"))
print(bbox(image))
Это работает в 5.3ms на моем Mac. Просто для удовольствия я проделал это с резьбой и запустил горизонтальную проекцию и вертикальную проекцию на отдельных параллельных нитях, и она снизилась до 3,6 мс с теми же результатами.
#!/usr/local/bin/python3
import numpy as np
from PIL import Image
import threading
import queue
def DoOneDim(image,axis,q):
"""Find bounding box of image"""
proj=np.any(image,axis=axis)
# Find first non-zero value
A=np.argmax(proj)
# And and last
B=image.shape[1-axis]-np.argmax(np.flipud(proj))-1
q.put({axis:(A,B)})
def bboxTh(image):
"""Threaded version of bbox() that does vertical and horizontal on their own theads"""
q = queue.Queue()
Hthread=threading.Thread(target=DoOneDim, args=(image,0,q))
Vthread=threading.Thread(target=DoOneDim, args=(image,1,q))
Hthread.start()
Vthread.start()
Hthread.join()
Vthread.join()
results=dict()
while not q.empty():
results.update(q.get())
return results
image=np.array(Image.open("a.png").convert("L"))
print(bboxTh(image))
Идентифицированная коробка выглядит так:
Поскольку вы ищете одну ограничивающую рамку, не используйте regionprops
или любая функция для каждого объекта. Это также делает так, что вам не нужно пытаться сделать один объект из всех желтых точек.
Самое простое решение здесь - это пройтись по изображению и для каждого пикселя определить, достаточно ли оно "желтого" (что бы это ни значило для вашего приложения). Если это так, добавьте координаты пикселя к расчету бегущей ограничительной рамки.
Расчет ограничительной рамки довольно прост:
top_left = [1e9, 1e9]
bottom_right = [0, 0]
for ...:
# within your loop over the pixels, [x, y] are the current coordinates
top_left = [min(top_left[0], x), min(top_left[1], y)];
bottom_right = [max(bottom_right[0], x), max(bottom_right[1], y)];
С лыжным магом может быть способ сделать это без петель, но я не знаю этого пакета вообще.