python - OpenCV 平滑轮廓
问题描述
我正在尝试解决使用 OpenCV 在徽标周围创建路径的问题。我附上了两张图片,tekst.png和tekst2.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)
解决方案
这是在 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()
阿尔法通道:
轮廓图像:
平滑扩张轮廓图像:
倒置轮廓模糊:
边缘图像:
结果:
推荐阅读
- sql - 转换为关系代数
- c++ - 当应用于不相关的指针时,std::less 如何比 < 更安全?
- ios - 斯威夫特用户界面 | 文本字段未读取输入的值
- c++ - 像这样初始化 int 向量有什么问题:vector
v1 = {1, 2, 3, 4}? - perl - Perl “do { ... } if ...” 作为表达式
- python - 如何引入while循环以计算月利率?
- ios - 架构 XXX 的未定义符号 - 在 Xcode 12.1 中
- javascript - OSX 上的 Chrome:CSS 过渡立即应用于 div 的第二个克隆
- python - 熊猫 for 循环太慢
- android - android如何使用intent将数据返回给mainActivity