首页 > 解决方案 > OpenCV 平滑轮廓

问题描述

我正在尝试解决使用 OpenCV 在徽标周围创建路径的问题。我附上了两张图片,tekst.pngtekst2.png。我还附上了一个图像compare.png,它显示了想要的结果(手动创建)和我目前用我的程序得到的结果。

如果有人对我有任何建议,我将不胜感激!

所需解决方案的简短描述:

我目前拥有的代码:


def current_milli_time():
    return round(time.time() * 1000)

def time_calculation_start():
    timing.append(current_milli_time())

def time_calculation_end(string):
    timing.append(current_milli_time())
    print(str(string) + ": ", timing[1] - timing[0], "ms")
    timing.clear()


def render_png(filename):
    print(filename)
    time_calculation_start()
    original_image = cv2.imread(str(filename), cv2.IMREAD_UNCHANGED)
    copy = original_image.copy() # Saved for imagecreation
    time_calculation_end("Setup")

    time_calculation_start()
    if(original_image.shape[2] == 4):
        b,g,r,mask = cv2.split(original_image)
    time_calculation_end("Mask")
    

    # Reduce outer turdss
    time_calculation_start()
    kernel = np.ones((3,3), np.uint8)
    dilation = cv2.dilate(mask,kernel,iterations = 2)
    dilation = cv2.erode(dilation,kernel,iterations = 1)
    time_calculation_end("Dialtion")
    time_calculation_start()
    gaublur = cv2.GaussianBlur(dilation,(16,16),0)
    time_calculation_end("Gaussian blur")


    #Find contours
    time_calculation_start()
    contours, hierarchy = cv2.findContours(gaublur, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    time_calculation_end("Find contours")
    
    print("\tContour layers: ", len(contours))


    # Draw contours
    time_calculation_start()
    cv2.drawContours(copy, contours, -1, (0, 255, 0, 255),1) 
    time_calculation_end("Draw contours")
    print("\n")

    cv2.imwrite(str(render_path) + str(filename), copy)

标签: pythonopencvsvgimage-processing

解决方案


这是在 Python/OpenCV 中执行此操作的一种方法。请注意,我减小了您输入的大小。

  • 读取输入
  • 提取 BGR 通道
  • 提取 Alpha 通道
  • 从 alpha 通道中获取最大轮廓以去除小区域
  • 减少顶点数量以使其更平滑
  • 在黑色背景上绘制白色填充轮廓
  • 扩大轮廓图像
  • 制作边缘图像并将其加厚
  • 制作白色背景图片
  • 反转扩张的轮廓并将其模糊为阴影
  • 在背景上覆盖模糊的扩张区域
  • 覆盖扩大的白色区域
  • 覆盖 bgr 图像
  • 覆盖边缘
  • 保存结果

输入:

在此处输入图像描述

import cv2
import numpy as np

# read image
img = cv2.imread('hjemsokt_small.png', cv2.IMREAD_UNCHANGED)

# extract bgr image
bgr = img[:,:,0:3]

# extract alpha channel
alpha = img[:,:,3]

# get largest contours
contours = cv2.findContours(alpha, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)

# smooth contour
peri = cv2.arcLength(big_contour, True)
big_contour = cv2.approxPolyDP(big_contour, 0.001 * peri, True)

# draw white filled contour on black background
contour_img = np.zeros_like(alpha)
cv2.drawContours(contour_img, [big_contour], 0, 255, -1)

# apply dilate to connect the white areas in the alpha channel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (40,40))
dilate = cv2.morphologyEx(contour_img, cv2.MORPH_DILATE, kernel)

# make edge outline
edge = cv2.Canny(dilate, 0, 200)

# thicken edge
edge = cv2.GaussianBlur(edge, (0,0), sigmaX=0.3, sigmaY=0.3)

# make background
result = np.full_like(bgr, (255,255,255))

# invert dilated image and blur
dilate_inv = 255 - dilate
dilate_inv = cv2.GaussianBlur(dilate_inv, (0,0), sigmaX=21, sigmaY=21)
dilate_inv = cv2.merge([dilate_inv,dilate_inv,dilate_inv])

# overlay blurred dilated area on background
result[dilate_inv>0] = dilate_inv[dilate_inv>0]

# overlay dilated white region
result[dilate==255] = (255,255,255)

# overlay bgr image
result[contour_img==255] = bgr[contour_img==255]

# overlay edge
result[edge!=0] = (96,96,96)

# save resulting images
cv2.imwrite('hjemsokt_small_alpha.jpg',alpha)
cv2.imwrite('hjemsokt_small_contour.jpg',contour_img)
cv2.imwrite('hjemsokt_small_alpha_dilated.jpg',dilate)
cv2.imwrite('hjemsokt_small_alpha_dilated_inv.jpg',dilate_inv)
cv2.imwrite('hjemsokt_small_alpha_dilated_edge.jpg',edge)
cv2.imwrite('hjemsokt_small_result.jpg',result)

# show thresh and result    
cv2.imshow("bgr", bgr)
cv2.imshow("alpha", alpha)
cv2.imshow("contour_img", contour_img)
cv2.imshow("dilate", dilate)
cv2.imshow("dilate_inv", dilate_inv)
cv2.imshow("edge", edge)
cv2.imshow("result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()

阿尔法通道:

在此处输入图像描述

轮廓图像:

在此处输入图像描述

平滑扩张轮廓图像:

在此处输入图像描述

倒置轮廓模糊:

在此处输入图像描述

边缘图像:

在此处输入图像描述

结果:

在此处输入图像描述


推荐阅读