python - 使图像边缘平滑

标签 python opencv image-processing

我目前正在做一个简单的项目

它正在删除任何图像的背景并将其转换为贴纸,但它并没有让我更平滑

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()
Working on this Image

这是输出图像


但我希望这个图像像这样更平滑

最佳答案

这是如何用一些彩色图像而不是 Python/OpenCV 中的透明度替换背景。

  • 阅读输入
  • 转为灰色
  • 阈值
  • 模糊然后将灰色拉伸(stretch)到黑色以消除锯齿
  • 获取外轮廓和最大轮廓
  • 在黑底白字上画出最大的等高线
  • 扩大以添加黑色边框(如果需要)
  • 创建彩色(红色)背景图像
  • 将掩码应用于输入
  • 将倒置蒙版应用到背景
  • 将两个结果相加
  • 保存结果

  • 输入:
    enter image description here
    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()
    

    阈值图像:
    enter image description here
    蒙版图片:
    enter image description here
    应用于图像的蒙版:
    enter image description here
    应用于背景的反转蒙版:
    enter image description here
    结果:
    enter image description here

    关于python - 使图像边缘平滑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63507755/

    相关文章:

    python - OpenCV:如何计算中心像素周围窗口的最小值?

    android - 比较忽略光线的图像android

    ruby-on-rails - 使用 Rmagick 或 ImageMagick 在背景上放置标题

    Python:使用泰勒级数逼近 ln(x)

    image-processing - 负差异值?

    matlab - 像素值和图像尺寸

    c# - WinRT 将 Jpg 或 PNG 转换为 GIF

    python - 搜索文件python

    javascript - 如何获取早于 1901 的时间戳

    Python 在关闭 GUI 应用程序时意外退出