Jak usunąć tło z tego rodzaju obrazu?
Chcę usunąć tło tego obrazu, aby uzyskać tylko osobę. Mam tysiące takich obrazów, w zasadzie osoba i nieco białawe tło.
To, co zrobiłem, to użycie detektora krawędzi, takiego jak canny edge detector lub sobel filter (z biblioteki skimage
). To, co myślę, że można zrobić, to wybielić piksele w krawędziach i przyciemnić piksele bez. Następnie oryginalny obraz można zamaskować, aby uzyskać zdjęcie osoby tylko.
EDIT:
Czy możliwe jest również usunięcie tła między prawą ręką a spódnicą i między włosami?
6 answers
Poniższy kod powinien cię rozpocząć. Możesz chcieć pobawić się parametrami u góry programu, aby dostroić swoją ekstrakcję:
import cv2
import numpy as np
#== Parameters =======================================================================
BLUR = 21
CANNY_THRESH_1 = 10
CANNY_THRESH_2 = 200
MASK_DILATE_ITER = 10
MASK_ERODE_ITER = 10
MASK_COLOR = (0.0,0.0,1.0) # In BGR format
#== Processing =======================================================================
#-- Read image -----------------------------------------------------------------------
img = cv2.imread('C:/Temp/person.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#-- Edge detection -------------------------------------------------------------------
edges = cv2.Canny(gray, CANNY_THRESH_1, CANNY_THRESH_2)
edges = cv2.dilate(edges, None)
edges = cv2.erode(edges, None)
#-- Find contours in edges, sort by area ---------------------------------------------
contour_info = []
_, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Previously, for a previous version of cv2, this line was:
# contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# Thanks to notes from commenters, I've updated the code but left this note
for c in contours:
contour_info.append((
c,
cv2.isContourConvex(c),
cv2.contourArea(c),
))
contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
max_contour = contour_info[0]
#-- Create empty mask, draw filled polygon on it corresponding to largest contour ----
# Mask is black, polygon is white
mask = np.zeros(edges.shape)
cv2.fillConvexPoly(mask, max_contour[0], (255))
#-- Smooth mask, then blur it --------------------------------------------------------
mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
mask = cv2.erode(mask, None, iterations=MASK_ERODE_ITER)
mask = cv2.GaussianBlur(mask, (BLUR, BLUR), 0)
mask_stack = np.dstack([mask]*3) # Create 3-channel alpha mask
#-- Blend masked img into MASK_COLOR background --------------------------------------
mask_stack = mask_stack.astype('float32') / 255.0 # Use float matrices,
img = img.astype('float32') / 255.0 # for easy blending
masked = (mask_stack * img) + ((1-mask_stack) * MASK_COLOR) # Blend
masked = (masked * 255).astype('uint8') # Convert back to 8-bit
cv2.imshow('img', masked) # Display
cv2.waitKey()
#cv2.imwrite('C:/Temp/person-masked.jpg', masked) # Save
Ouput:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 17:18:47
Jeśli chcesz wypełnić tło nie czerwonym kolorem, ale uczynić je przezroczystym, możesz dodać następujące linie do rozwiązania:
# split image into channels
c_red, c_green, c_blue = cv2.split(img)
# merge with mask got on one of a previous steps
img_a = cv2.merge((c_red, c_green, c_blue, mask.astype('float32') / 255.0))
# show on screen (optional in jupiter)
%matplotlib inline
plt.imshow(img_a)
plt.show()
# save to disk
cv2.imwrite('girl_1.png', img_a*255)
# or the same using plt
plt.imsave('girl_2.png', img_a)
Jeśli chcesz, możesz dostosować niektóre parametry kompresji png, aby zmniejszyć plik.
Obraz na białym tle poniżej. Lub na czarnym - http://imgur.com/a/4NwmH
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-08 21:06:10
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-11 06:11:27
przykład pracy z vs2017.
Ustawia czerwone tło, ale zapisuje niebieskie..
Dodano również przykład transperent w.
Jak mogę usunąć ciało dziewczyny i zostawić tylko sukienkę na zdjęciu? Jakieś pomysły?
# == https://stackoverflow.com/questions/29313667/how-do-i-remove-the-background-from-this-kind-of-image
import cv2
import numpy as np
from matplotlib import pyplot as plt
#== Parameters =======================================================================
BLUR = 21
CANNY_THRESH_1 = 10
CANNY_THRESH_2 = 200
MASK_DILATE_ITER = 10
MASK_ERODE_ITER = 10
MASK_COLOR = (0.0,0.0,1.0) # In BGR format
#== Processing =======================================================================
#-- Read image -----------------------------------------------------------------------
img = cv2.imread('img/SYxmp.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#-- Edge detection -------------------------------------------------------------------
edges = cv2.Canny(gray, CANNY_THRESH_1, CANNY_THRESH_2)
edges = cv2.dilate(edges, None)
edges = cv2.erode(edges, None)
#-- Find contours in edges, sort by area ---------------------------------------------
contour_info = []
_, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
for c in contours:
contour_info.append((
c,
cv2.isContourConvex(c),
cv2.contourArea(c),
))
contour_info = sorted(contour_info, key=lambda c: c[2], reverse=True)
max_contour = contour_info[0]
#-- Create empty mask, draw filled polygon on it corresponding to largest contour ----
# Mask is black, polygon is white
mask = np.zeros(edges.shape)
cv2.fillConvexPoly(mask, max_contour[0], (255))
#-- Smooth mask, then blur it --------------------------------------------------------
mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
mask = cv2.erode(mask, None, iterations=MASK_ERODE_ITER)
mask = cv2.GaussianBlur(mask, (BLUR, BLUR), 0)
mask_stack = np.dstack([mask]*3) # Create 3-channel alpha mask
#-- Blend masked img into MASK_COLOR background --------------------------------------
mask_stack = mask_stack.astype('float32') / 255.0 # Use float matrices,
img = img.astype('float32') / 255.0 # for easy blending
masked = (mask_stack * img) + ((1-mask_stack) * MASK_COLOR) # Blend
masked = (masked * 255).astype('uint8') # Convert back to 8-bit
plt.imsave('img/girl_blue.png', masked)
# split image into channels
c_red, c_green, c_blue = cv2.split(img)
# merge with mask got on one of a previous steps
img_a = cv2.merge((c_red, c_green, c_blue, mask.astype('float32') / 255.0))
# show on screen (optional in jupiter)
#%matplotlib inline
plt.imshow(img_a)
plt.show()
# save to disk
cv2.imwrite('img/girl_1.png', img_a*255)
# or the same using plt
plt.imsave('img/girl_2.png', img_a)
cv2.imshow('img', masked) # Displays red, saves blue
cv2.waitKey()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-03 09:25:28
Zgodnie z odpowiedzią @jedwards, gdy używasz z opencv4, będziesz miał ten błąd:
Traceback (most recent call last):
File "save.py", line 26, in <module>
_, contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
ValueError: not enough values to unpack (expected 3, got 2)
Funkcja cv2.findContours()
została zmieniona, aby zwracać tylko kontury i hierarchię
Powinieneś zmienić na to:
contours, _ = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-29 04:46:50
Po uzyskaniu niekompletnych krawędzi (tak jak masz), możesz uruchomić morfologię zamykającą (sekwencję rozszerzania i erodowania) (będzie musiał ustawić rozmiar i iteracje w oparciu o potrzeby/stan krawędzi).
Teraz zakładając, że masz stałą krawędź wokół obiektu, użyj dowolnego algorytmu wypełnienia (blob), aby połączyć wszystkie punkty poza obiektem o krawędziach, a następnie weź negatyw tego, aby dać maskę wnętrza obiektu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-30 20:07:17