Machen Sie Kanten des Bildes glatt
Ich arbeite gerade an einem einfachen Projekt.
Es entfernt den Hintergrund eines Bildes und konvertiert es in einen Aufkleber, aber es macht mich nicht glatter
import cv2
import numpy as np
from PIL import Image, ImageFilter
from google.colab.patches import cv2_imshow
from matplotlib import pyplot as pl
#img = cv2.imread("/content/police-car-icon-cartoon-style-vector-16884775.jpg")
remove_background("/content/WhatsApp Image 2020-08-17 at 1.08.33 AM (2).jpeg")
def remove_background(img1):
#== Parameters =======================================================================
BLUR = 5
CANNY_THRESH_1 = 10
CANNY_THRESH_2 = 100
MASK_DILATE_ITER = 10
MASK_ERODE_ITER = (1,1)
MASK_COLOR = (220,220,220) # In BGR format
#== Processing =======================================================================
#-- Read image -----------------------------------------------------------------------
img = cv2.imread(img1)
#img = cv2.resize(img, (600,600))
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)
#-- Create empty mask, draw filled polygon on it corresponding to largest contour ----
# Mask is black, polygon is white
mask = np.zeros(edges.shape)
for c in contour_info:
cv2.fillConvexPoly(mask, c[0], (255))
# cv2.fillConvexPoly(mask, max_contour[0], (255))
#-- Smooth mask, then blur it --------------------------------------------------------
mask = cv2.dilate(mask, None, iterations=MASK_DILATE_ITER)
mask_stack = np.dstack([mask]*3) # Create 3-channel alpha mask
mask_u8 = np.array(mask,np.uint8)
back = np.zeros(mask.shape,np.uint8)
back[mask_u8 == 0] = 255
border = cv2.Canny(mask_u8, CANNY_THRESH_1, CANNY_THRESH_2)
border = cv2.dilate(border, None, iterations=3)
masked = mask_stack * img # Blend
masked = (masked * 255).astype('uint8')
# background Colors (blue,green,red)
masked[:,:,0][back == 255] = 190
masked[:,:,1][back == 255] = 190
masked[:,:,2][back == 255] = 190
cv2.imwrite('img.png', masked)
cv2_imshow( masked)
cv2.waitKey(0)
cv2.destroyAllWindows()
Dies ist das Ausgabebild
Aber ich möchte, dass dieses Bild so etwas glatter wird
Antworten
Hier erfahren Sie, wie Sie den Hintergrund in Python / OpenCV durch ein farbiges Bild anstelle von Transparenz ersetzen.
- Lesen Sie die Eingabe
- In grau konvertieren
- Schwelle
- Unschärfe strecken sich dann grau zu schwarz zu Antialien
- Holen Sie sich die Außenkonturen und die größte Kontur
- Zeichnen Sie die größte Kontur als Weiß auf schwarzem Hintergrund
- Erweitern Sie, um Ihren schwarzen Rand hinzuzufügen (falls gewünscht)
- Erstellen Sie ein farbiges (rotes) Hintergrundbild
- Wenden Sie die Maske auf die Eingabe an
- Wenden Sie die invertierte Maske auf den Hintergrund an
- Addieren Sie die beiden Ergebnisse
- Speichern Sie das Ergebnis
Eingang:
import cv2
import numpy as np
import skimage.exposure
# load image
img = cv2.imread('bunny.jpg')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 32, 255, cv2.THRESH_BINARY)[1]
# blur threshold image
blur = cv2.GaussianBlur(thresh, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
stretch = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.uint8)
# threshold again
thresh2 = cv2.threshold(stretch, 0, 255, cv2.THRESH_BINARY)[1]
# get external contour
contours = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw white filled contour on black background
contour = np.zeros_like(thresh, dtype=np.uint8)
cv2.drawContours(contour, [big_contour], 0, 255, -1)
# dilate mask for dark border
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
mask = cv2.morphologyEx(contour, cv2.MORPH_DILATE, kernel)
# create red colored background image
bckgrnd = np.full_like(img, (0,0,255), dtype=np.uint8)
# apply mask to img
img_masked = cv2.bitwise_and(img, img, mask=mask)
# apply inverse mask to colored background image
bckgrnd_masked = cv2.bitwise_and(bckgrnd, bckgrnd, mask=255-mask)
# combine the two
result = cv2.add(img_masked, bckgrnd_masked)
# save output
cv2.imwrite('bunny_thresh2.png', thresh)
cv2.imwrite('bunny_mask2.png', mask)
cv2.imwrite('bunny_masked2.png', img_masked)
cv2.imwrite('bunny_background_masked2.png', bckgrnd_masked)
cv2.imwrite('bunny_result2.png', result)
# Display various images to see the steps
cv2.imshow('gray',gray)
cv2.imshow('thresh', thresh)
cv2.imshow('blur', blur)
cv2.imshow('stretch', stretch)
cv2.imshow('thresh2', thresh2)
cv2.imshow('contour', contour)
cv2.imshow('mask', mask)
cv2.imshow('img_masked', img_masked)
cv2.imshow('bckgrnd_masked', bckgrnd_masked)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Schwellenwertbild:
Maskenbild:
Maske auf Bild angewendet:
Invertierte Maske auf Hintergrund angewendet:
Ergebnis:
Hier ist eine Möglichkeit, Alpha-Kanal-Antialiasing in Python / OpenCV durchzuführen
- Lesen Sie die Eingabe
- In Graustufen konvertieren
- Schwellenwert zum Erstellen einer Maske
- verwischen
- Dehnen Sie den Kontrast so, dass Mittelgrau zu Schwarz wird
- Wieder Schwelle
- Holen Sie sich Außenkontur
- Zeichnen Sie eine weiße gefüllte Kontur auf schwarzem Hintergrund
- Dilatieren Sie für dunkle Grenze
- Nochmals leicht verwischen
- Dehnen Sie den Kontrast so, dass das mittlere Grau als Maske schwarz wird
- Legen Sie die Maske in den Alpha-Kanal des Eingangs
- Ergebnisse speichern
Eingang:
import cv2
import numpy as np
import skimage.exposure
# load image
img = cv2.imread('bunny.jpg')
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold
thresh = cv2.threshold(gray, 32, 255, cv2.THRESH_BINARY)[1]
# blur threshold image
blur = cv2.GaussianBlur(thresh, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
stretch = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255)).astype(np.uint8)
# threshold again
thresh2 = cv2.threshold(stretch, 0, 255, cv2.THRESH_BINARY)[1]
# get external contour
contours = cv2.findContours(thresh2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw white filled contour on black background as mas
contour = np.zeros_like(gray)
cv2.drawContours(contour, [big_contour], 0, 255, -1)
# dilate mask for dark border
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (20,20))
dilate = cv2.morphologyEx(contour, cv2.MORPH_DILATE, kernel)
# blur dilate image
blur2 = cv2.GaussianBlur(dilate, (3,3), sigmaX=0, sigmaY=0, borderType = cv2.BORDER_DEFAULT)
# stretch so that 255 -> 255 and 127.5 -> 0
mask = skimage.exposure.rescale_intensity(blur2, in_range=(127.5,255), out_range=(0,255))
# put mask into alpha channel of input
result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
result[:,:,3] = mask
# save output
cv2.imwrite('bunnyman_thresh.png', thresh)
cv2.imwrite('bunny_mask.png', mask)
cv2.imwrite('bunny_antialiased.png', result)
# Display various images to see the steps
cv2.imshow('gray',gray)
cv2.imshow('thresh', thresh)
cv2.imshow('blur', blur)
cv2.imshow('stretch', stretch)
cv2.imshow('thresh2', thresh2)
cv2.imshow('contour', contour)
cv2.imshow('dilate', dilate)
cv2.imshow('mask', mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Schwellenwertbild:
Maskenbild:
Ergebnis:
Würde ein Dithering-Algorithmus funktionieren? Hier ist eine PIL-Erweiterung für Dithering:https://github.com/hbldh/hitherdither