Добавить отступ к объекту в 4-канальном изображении

У меня есть 4-канальное изображение (.png, .tif), подобное этому:

введите здесь описание изображения

Я использую OpenCV и хочу добавить отступ типа BORDER_REFLECT вокруг цветка. copyMakeBorder бесполезен, так как добавляет отступы к краям изображения.

Я могу добавить определенные отступы, если я разделю изображение в bgr + alpha и применю dilate с опцией BORDER_REFLECT к изображению bgr, но это решение портит все пиксели цветка.

Есть ли способ выполнить выборочное добавление заполнения BORDER_REFLECT для области интереса, определенной двоичной маской?

ИЗМЕНИТЬ:

Результат, который я ожидаю, будет примерно таким (извините, я очень быстро нарисовал его с помощью GIMP):

введите здесь описание изображения

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


person Finfa811    schedule 16.03.2016    source источник
comment
Не могли бы вы показать ожидаемый результат?   -  person Miki    schedule 16.03.2016
comment
Я не могу показать правильный ожидаемый результат, потому что это идея получить его программно, но я отредактировал вопрос, чтобы показать приблизительный результат, который я нарисовал с помощью GIMP. Извините за неточность, но я сделал это очень быстро, но надеюсь, вы сможете понять желаемый результат.   -  person Finfa811    schedule 16.03.2016
comment
Красиво, теперь намного понятнее. Нет, это не то, что вы можете сделать с copymakeborder. Даже с dilate или подобным, наверное. Интересно, однако.   -  person Miki    schedule 16.03.2016
comment
Быстрый хак, вероятно, может заключаться в том, чтобы нарисовать оригинальный цветок поверх цветка немного большего размера. вы можете сделать это с помощью resize   -  person Miki    schedule 16.03.2016
comment
Это я пробовал, но с этим решением заполнение похоже на стиль BORDER_WRAP (cdefgh|abcdefgh). А меня интересует BORDER_REFLECT мод, т. е. зеркалирование пикселей (fedcba|abcdefgh). Я знаю, что проблема непростая, но у меня заканчиваются идеи :(   -  person Finfa811    schedule 16.03.2016
comment
@ Finfa811, если вы хотите добавить так мало, лучше всего просто масштабировать изображение на несколько процентов. любое другое решение вызовет у вас головную боль, потому что вам придется избавиться от границы между цветком и недавно добавленными вещами.   -  person Piglet    schedule 16.03.2016
comment
Да, это звучит разумно @Piglet. Финфа, зачем тебе это? Можете ли вы объяснить свое основное приложение?   -  person Miki    schedule 16.03.2016
comment
и я хотел бы добавить, что любое другое решение, кроме масштабирования всего цветка, будет выглядеть глупо и неестественно. независимо от того, насколько хорош ваш алгоритм. чем больше вы добавите, тем скорее вы поймете, что что-то было добавлено. Вы также можете извлечь лепестки, масштабировать их, немного повернуть и поместить позади исходного цветка, чтобы он выглядел как второй слой лепестков. Я думаю, это было бы лучшим решением   -  person Piglet    schedule 16.03.2016
comment
@Piglet идея состоит в том, чтобы иметь общее решение для заполнения определенного количества пикселей. На самом деле границу между цветком и новым материалом можно легко обнаружить, используя альфа-канал изображения, потому что у нас есть бинарная маска, которая сегментирует передний план и фон.   -  person Finfa811    schedule 16.03.2016
comment
Вероятно, вы можете использовать для этого закрашивание без заново изобретать колесо   -  person Miki    schedule 16.03.2016
comment
@ Finfa811, конечно, вы можете легко обнаружить границу, но можете ли вы удалить ее, чтобы не видеть перехода между старым и новым? Вам придется добавлять и удалять тени и блики довольно сложным образом, чтобы все выглядело хорошо. Вы можете масштабировать лепестки, чтобы получить определенное количество новых пикселей.   -  person Piglet    schedule 16.03.2016
comment
@Miki главное - это смешивание текстур. Если я хочу использовать пирамидальное (или многополосное) смешивание, размытие и изменение размера цветка внесет артефакты в конечный результат, поэтому мне нужно добавить определенные отступы на передний план, а зеркальная граница обеспечивает наилучшие результаты.   -  person Finfa811    schedule 16.03.2016
comment
Спасибо вам обоим, я попробую с inpaint.   -  person Finfa811    schedule 16.03.2016
comment
@ Finfa811, а испорченные зеркальные пиксели не вызовут никаких артефактов? Я не верю в это. В любом случае большая его часть будет плохо интерполирована, потому что окружность увеличивается с каждым добавляемым пикселем.   -  person Piglet    schedule 16.03.2016
comment
Если вы добавите отступы и сохраните исходную маску, это позволит избежать размытия черных пикселей на фоне с передним планом. На самом деле это метод, который использует конвейер сшивания OpenCV после деформации изображений. Я хочу применить его к смешиванию текстур.   -  person Finfa811    schedule 16.03.2016


Ответы (2)


Простой скрипт на Python для изменения размера изображения и копирования оригинала поверх увеличенного сделает свое дело.

import cv2

img = cv2.imread('border_reflect.png', cv2.IMREAD_UNCHANGED)

pad = 20
sh = img.shape
sh_pad = (sh[0]+pad, sh[1]+pad)
imgpad = cv2.resize(img, sh_pad)

imgpad[20:20+sh[0], 20:20+sh[1], :][img[:,:,3]==255] = img[img[:,:,3]==255]
cv2.imwrite("padded_image.png", imgpad)

Вот результат

введите здесь описание изображения

Но это не выглядит очень «по центру». Поэтому я изменил код для обнаружения и учета смещений при копировании.

import cv2

img = cv2.imread('border_reflect.png', cv2.IMREAD_UNCHANGED)

pad = 20
sh = img.shape
sh_pad = (sh[0]+pad, sh[1]+pad)
imgpad = cv2.resize(img, sh_pad)

def get_roi(img):
    cimg = img[:,:,3].copy()

    contours,hierarchy = cv2.findContours(cimg,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

    #Remove the tiny pixel noises that get detected as contours
    contours = [cnt for cnt in contours if cv2.contourArea(cnt) > 10]

    x,y,w,h = cv2.boundingRect(cnt)
    roi=img[y:y+h,x:x+w]
    return roi

roi = get_roi(img)
roi2 = get_roi(imgpad)

sh = roi.shape
sh2 = roi2.shape

o = ((sh2[0]-sh[0])/2, (sh2[1]-sh[1])/2)

roi2[o[0]:o[0]+sh[0], o[1]:o[1]+sh[1], :][roi[:,:,3]==255] = roi[roi[:,:,3]==255]
cv2.imwrite("padded_image.png", imgpad)

Теперь выглядит намного лучше

введите здесь описание изображения

person Vasanth    schedule 16.03.2016
comment
Спасибо за ваш ответ. Я попробовал это в качестве первого подхода, но на самом деле реальное решение более сложное, поскольку пиксели с отступами должны отражаться от цветка. - person Finfa811; 16.03.2016
comment
Только что увидел вашу правку. Как заметил Пятачок, зеркальное отражение пикселей цветка сделало бы тени вокруг лепестков неестественными, а также примите во внимание постоянно увеличивающееся размытие из-за нехватки пикселей во внутренних областях. Его решение добавить вращение перед суммированием, вероятно, дало бы лучший результат для этого примера. Внедрение зеркального отображения повлечет за собой небольшой рост региона. Попробую это, если у меня будет время просто для удовольствия :). - person Vasanth; 16.03.2016

Проблема уже рассматривалась и решалась здесь:

http://answers.opencv.org/question/90229/add-padding-to-object-in-4-channel-image/

person Finfa811    schedule 08.04.2016