Обрезанные перья края - PullRequest
2 голосов
/ 03 мая 2019

Я пытаюсь вырезать объект из изображения и вставить его на другое изображение.Изучая метод в этом ответе , мне удалось это сделать.Например:

crop steps

Код ( show_mask_applied.py ):

import sys
from pathlib import Path
from helpers_cv2 import *
import cv2
import numpy

img_path = Path(sys.argv[1])

img      = cmyk_to_bgr(str(img_path))
threshed = threshold(img, 240, type=cv2.THRESH_BINARY_INV)
contours = find_contours(threshed)
mask     = mask_from_contours(img, contours)
mask     = dilate_mask(mask, 50)
crop     = cv2.bitwise_or(img, img, mask=mask)

bg      = cv2.imread("bg.jpg")
bg_mask = cv2.bitwise_not(mask)
bg_crop = cv2.bitwise_or(bg, bg, mask=bg_mask)

final   = cv2.bitwise_or(crop, bg_crop)

cv2.imshow("debug", final)

cv2.waitKey(0)
cv2.destroyAllWindows()

helpers_cv2.py :

from pathlib import Path
import cv2
import numpy
from PIL import Image
from PIL import ImageCms
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

def cmyk_to_bgr(cmyk_img):
    img = Image.open(cmyk_img)
    if img.mode == "CMYK":
        img = ImageCms.profileToProfile(img, "Color Profiles\\USWebCoatedSWOP.icc", "Color Profiles\\sRGB_Color_Space_Profile.icm", outputMode="RGB")
    return cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2BGR)

def threshold(img, thresh=128, maxval=255, type=cv2.THRESH_BINARY):
    if len(img.shape) == 3:
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    threshed = cv2.threshold(img, thresh, maxval, type)[1]
    return threshed

def find_contours(img):
    kernel   = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
    morphed  = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
    contours = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    return contours[-2]

def mask_from_contours(ref_img, contours):
    mask = numpy.zeros(ref_img.shape, numpy.uint8)
    mask = cv2.drawContours(mask, contours, -1, (255,255,255), -1)
    return cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)

def dilate_mask(mask, kernel_size=11):
    kernel  = numpy.ones((kernel_size,kernel_size), numpy.uint8)
    dilated = cv2.dilate(mask, kernel, iterations=1)
    return dilated

Теперь вместо острых краев я хочу обрезать края с перьями / гладкими.Например (правильный; создан в Photoshop):

sharp vs feathered

Как я могу это сделать?


Все изображения и коды можно найти в этом хранилище .

Ответы [ 2 ]

6 голосов
/ 03 мая 2019

Вы используете маску для выбора частей наложенного изображения. Маска в настоящее время выглядит так:

enter image description here

Давайте сначала добавим размытие по Гауссу к этой маске.

mask_blurred  = cv2.GaussianBlur(mask,(99,99),0)

Дойдем до этого:

enter image description here

Теперь оставшаяся задача состоит в том, чтобы смешать изображений, используя альфа-значение в маске, а не использовать его в качестве логического оператора, как вы делаете в настоящее время.

mask_blurred_3chan = cv2.cvtColor(mask_blurred, cv2.COLOR_GRAY2BGR).astype('float') / 255.
img = img.astype('float') / 255.
bg = bg.astype('float') / 255.
out  = bg * (1 - mask_blurred_3chan) + img * mask_blurred_3chan

Приведенный выше фрагмент довольно прост. Сначала преобразуйте маску в 3-канальное изображение (так как мы хотим замаскировать все каналы). Затем преобразуйте изображения в плавающее, поскольку маскирование выполняется в плавающей точке Последняя строка выполняет фактическую работу: для каждого пикселя смешиваются изображения bg и img в соответствии со значением в маске. Результат выглядит так:

enter image description here

Количество растушевки определяется размером ядра в размытии по Гауссу. Обратите внимание, что это должно быть нечетное число.

После этого out (окончательное изображение) все еще находится в плавающей точке. Его можно преобразовать обратно в int, используя:

out = (out * 255).astype('uint8')
0 голосов
/ 06 мая 2019

Хотя ответа Paul92 более чем достаточно, я все равно хотел опубликовать свой код для любого будущего посетителя.

Я делаю обрезку, чтобы избавиться от белого фона на фотографиях некоторых продуктов. Итак, главная цель - избавиться от белого, сохранив при этом продукт в целости и сохранности. У большинства фотографий продукта есть тени на земле. Это либо сама земля (выцветшая), либо тень продукта, либо и то и другое.

Хотя обнаружение объекта работает нормально, эти тени также считаются частью объекта. Дифференцировать тени от объектов на самом деле не нужно, но это приводит к некоторым изображениям, которые не столь желательны. Например, изучите левую и нижнюю стороны изображения (тень). Срез / обрезка явно видны и выглядят не так хорошо.

shadow cut

Чтобы обойти эту проблему, я хотел делать непрямоугольные посевы. Использование масок, кажется, делает работу просто отлично. Следующая проблема состояла в том, чтобы сделать обрезку с заштрихованными / размытыми краями, чтобы я мог избавиться от этих видимых теней. С помощью справки из Пол92 мне удалось это сделать. Пример вывода (обратите внимание на отсутствующие тени, края более мягкие):

softer edges

Операции с изображениями:

image operations

код ( show_mask_feserved.py , helpers_cv2.py )

import sys
from pathlib import Path
import cv2
import numpy
from helpers_cv2 import *

img_path = Path(sys.argv[1])

img      = cmyk_to_bgr(str(img_path))
threshed = threshold(img, 240, type=cv2.THRESH_BINARY_INV)
contours = find_contours(threshed)

dilation_length = 51
blur_length     = 51

mask         = mask_from_contours(img, contours)
mask_dilated = dilate_mask(mask, dilation_length)
mask_smooth  = smooth_mask(mask_dilated, odd(dilation_length * 1.5))
mask_blurred = cv2.GaussianBlur(mask_smooth, (blur_length, blur_length), 0)
mask_blurred = cv2.cvtColor(mask_blurred, cv2.COLOR_GRAY2BGR)

mask_threshed = threshold(mask_blurred, 1)
mask_contours = find_contours(mask_threshed)
mask_contour  = max_contour(mask_contours)

x, y, w, h   = cv2.boundingRect(mask_contour)

img_cropped  = img[y:y+h, x:x+w]
mask_cropped = mask_blurred[y:y+h, x:x+w]
background   = numpy.full(img_cropped.shape, (200,240,200), dtype=numpy.uint8)
output       = alpha_blend(background, img_cropped, mask_cropped)
...