Ускорение за цикл пикселей в OpenCV Python - PullRequest
0 голосов
/ 21 июня 2019

Поэтому я пытаюсь найти пиксели, которые не являются белыми, и создать ограничивающую рамку вокруг изображения, изучая цвета.Я хочу получить самый верхний, самый нижний, самый левый и самый правый небелые пиксели и использовать их для создания ограничивающего прямоугольника.Я использовал четыре цикла для прохождения каждой стороны. Также я хочу удалить фоновый цвет (цвет фона в основном серый) и изменить его на чисто белый.Я реализовал всю функциональность, но теперь, поскольку я использую много циклов, код работает слишком медленно.Мне нужно оптимизировать циклы, сохраняя при этом функциональность: находить самые верхние, самые нижние, самые левые и самые правые небелые пиксели и удалять цвета.Как я могу это сделать?

Приведенный ниже код показывает, что я делаю, чтобы одновременно получить ограничивающий прямоугольник и удаление фона.Маска представляет собой черно-белую версию изображения.Если это маска [i] [j] == 0, то это другой цвет, и поэтому мне нужно взять значение и сравнить его со значениями, хранящимися в p.Это помогает мне найти ограничивающую рамку.И если маска [i] [j]! = 0, тогда я изменяю значения изображения на белый.

//for bounding box
p = []
p.append(5000)
p.append(0)
p.append(5000)
p.append(0)


for i in range(0, height):
    for j in range(0, width):
        if mask[i][j] == 0:
            if j < p[0]:
                p[0] = j
            break
        else:
            img[i, j] = [255, 255, 255]

for i in range(0, height):
    for j in reversed(range(0, width)):
        if mask[i][j] == 0:
            if j > p[1]:
                p[1] = j
            break
        else:
            img[i, j] = [255, 255, 255]

//topdown
for i in range(0, width):
    for j in range(0, height):
        if mask[j][i] == 0:
            if j < p[2]:
                p[2] = j
            break
        else:
            img[j, i] = [255, 255, 255]

for i in reversed(range(0, width)):
    for j in reversed(range(0, height)):
        if mask[j][i] == 0:
            if j > p[3]:
                p[3] = j
            break
        else:
            img[j, i] = [255, 255, 255]

Так как я могу оптимизировать эти циклы, сохраняя при этом ту же функциональность получения пикселязначения и возможность изменить цвет другого изображения?

Ответы [ 2 ]

1 голос
/ 21 июня 2019

Фон
Чтобы сделать фон белым, вы можете использовать побитовую операцию с маской.Чтобы автоматизировать создание маски, прочитайте здесь .

Пример:
enter image description here

import cv2
import numpy as np

# load image and mask
img = cv2.imread('image.png')
mask = cv2.imread('mask.png')

# combine images
res = cv2.bitwise_or(img,mask)

cv2.imshow("result", res)
cv2.waitKey(0)
cv2.destroyAllWindows() 

Маска должна иметьравное количество цветовых каналов как изображение.Все белые области в маске также станут белыми на изображении.Черные области маски не будут затронуты на изображении.

Ограничительная рамка
Чтобы получить ограничительную рамку, вы можете использовать findContours .Он принимает двоичную маску в качестве входных данных и возвращает список контуров.Вы можете использовать контур, чтобы найти ограничивающий прямоугольник, повернутый ограничивающий прямоугольник или минимальный окружающий круг .Результат может быть не идеальным в зависимости от вашего ввода, но вы можете использовать его для повышения производительности, поскольку это значительно сужает поиск.

Примечание: вход для findContours должен иметь черный фон.Вы можете изменить свою маску, используя inverted_mask = cv2.bitwise_not(mask).Или, если вы получили маску с помощью порогового значения, вы можете выбрать инвертированный тип порога .

Результат:
enter image description here

Код:

    import cv2
    import numpy as np

    # load image // use your mask instead
    mask = cv2.imread('mask.png',0)

    # find contours 
    contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
        # get the boundingrect and draw a red line over it
        x,y,w,h = cv2.boundingRect(cnt)
        cv2.rectangle(mask2,(x,y),(x+w,y+h),(0,0,255),3)
        # get the minumum enclosing rectangle and draw it in blue
        rect = cv2.minAreaRect(cnt)
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        cv2.drawContours(mask2,[box],0,(255,0,0),3)

    # diplay result
    cv2.imshow("img", mask)
    cv2.waitKey(0)
    cv2.destroyAllWindows() 

Математика
Если выВместо того, чтобы проверять значения массива, вы можете повысить производительность, сначала суммируя строки и столбцы.Суммирование происходит быстро (и превращается в ноль), и теперь вы можете отбросить строки / столбцы, проверив одно значение.Вы можете увидеть пример этого процесса в этом ответе .Для этого я бы предложил использовать маску с черным фоном, так как вы можете сравнить сумму с нулем.По сути, это приведет к появлению красного ограничивающего прямоугольника вышеКонечно, когда найдена ненулевая строка / столбец, вам все равно придется зациклить ее, чтобы найти точную координату.

Pfiew, который оказался намного длиннее, чем предполагалось ...

0 голосов
/ 21 июня 2019

@ Джон Колеман имеет смысл. Вложенные циклы Python будут относительно медленными даже при использовании лучших алгоритмов, и есть библиотеки, которые могут оптимизировать такие операции.

Сам алгоритм можно ускорить, используя результаты каждого цикла, чтобы ограничить диапазон следующего цикла. Например, если при поиске верхнего небелого пикселя вы сканировали сверху вниз в качестве внешнего цикла и слева направо в качестве внутреннего цикла, то нашли пиксель (a, b) (с a - расстояние от верхнего ), затем в следующем разделе вы пошли искать левый пиксель, вы знаете, что вы можете начать сканирование с + 1 в верхнем нижнем внешнем цикле и не дальше, чем b - 1 в лево-правом внутреннем цикле. Назовем результат (c, d).

Точно так же нижний пиксель может быть не меньше c по вертикали и d по горизонтали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...