OpenCV获取不规则区域的最大内切圆部分问题个人思考笔记

接上面那篇文章基于OPENCV的任意多边形最大内切圆和最小外接圆-CSDN博客不是说用了一个大佬的代码吗(OpenCV获取不规则区域的最大内切圆(附Python / C++ 源码)),遇到些许问题以及自己的改进

首先这个大佬用的方法确实给我极大的帮助我之前使用的指令方式成成的内切圆要么出不来,要么超了,如下

改了很久都没有效果,最终看到了大佬的这篇文章,它的核心思路是这样的

【1】将目标轮廓/区域提取出来,处理成二值图:目标区域白色(255),背景黑色(0),并将目标区域填充为白色(255)。然后再二值化 + 轮廓提取 + 填充绘制:

【2】距离变换:获取距离变换结果最大值及其坐标。

【3】绘制结果:距离变换结果最大值为半径,对应位置为内切圆圆心。

但是最后绘制的时候出现了这样的情况

最终检查发现在原代码的这块出现了问题

contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
mask = np.zeros(gray.shape, np.uint8)
cv2.drawContours(mask, contours, 0, (255, 255, 255), -1)
cv2.imshow('mask', mask)

代码里面的

cv2.drawContours(mask,contours,0,(255,255,255),-1) 的作用是在指定的图像 mask 上绘制指定的轮廓,我怀疑是他没能很好的扣下轮廓,导致了后面没有顺利进行。

所以我就自己加了一部分内容让边界条件更加突出例如

# 使用 Canny 边缘检测获取更多的边缘信息

# 闭运算

# 使用高斯模糊平滑 mask

最后才寻找轮廓并创建掩膜

最终效果明显变好如下图

完整代码如下(和上篇一样)

import os
import cv2
import numpy as np

# 读取图像并缩小尺寸
src = cv2.imread('D:/WORK/PY/edge_processing(2)/train/screenshot4.jpg')
src_resized = cv2.resize(src, (800, 600))  # 将图像缩小到800x600

# 显示原始图像
cv2.imshow('src', src_resized)

# 将图像转换为灰度图像并进行阈值处理
gray = cv2.cvtColor(src_resized, cv2.COLOR_BGR2GRAY)
gray[gray > 127] = 255
cv2.imshow('thres', gray)

# 使用 Canny 边缘检测获取更多的边缘信息
edges = cv2.Canny(gray, 50, 150)
cv2.imshow('edges', edges)

# 闭运算
kernel = np.ones((5, 5), np.uint8)
closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
cv2.imshow('closed', closed)

# 使用高斯模糊平滑 mask
smoothed = cv2.GaussianBlur(closed, (5, 5), 0)

# 寻找轮廓并创建掩膜
contours, _ = cv2.findContours(smoothed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 获取多边形轮廓的坐标点
polygon_points = contours[0].squeeze()

# 在图像上绘制多边形轮廓
cv2.polylines(src_resized, [polygon_points], isClosed=True, color=(255, 0, 0), thickness=2)

# 绘制轮廓点坐标的蓝色线段
for point in polygon_points:
    x, y = point
    cv2.circle(src_resized, (x, y), 2, (255, 0, 0), -1)

# 轮廓近似
epsilon = 0.02 * cv2.arcLength(contours[0], True)  # 调整 epsilon 的值
approx = cv2.approxPolyDP(contours[0], epsilon, True)

mask = np.zeros(gray.shape, np.uint8)
cv2.drawContours(mask, [approx], 0, (255, 255, 255), -1)
cv2.imshow('mask', mask)

# 计算距离变换并将结果转换为灰度图像
dt = cv2.distanceTransform(mask, cv2.DIST_L2, 5, cv2.DIST_LABEL_PIXEL)
transImg = cv2.convertScaleAbs(dt)
cv2.normalize(transImg, transImg, 0, 255, cv2.NORM_MINMAX)
cv2.imshow("distanceTransform", transImg)

# 寻找最大内接圆
_, max_val, _, max_loc = cv2.minMaxLoc(dt)
radius = int(max_val)

# 调整半径以确保不超出图像边界
max_radius = min(radius, min(src_resized.shape[0], src_resized.shape[1]) // 2)

# 在原始图像上画出最大内接圆
max_loc = (int(max_loc[0]), int(max_loc[1]))  # 将 max_loc 中的浮点数值转换为整数值
cv2.circle(src_resized, max_loc, max_radius, (0, 0, 255), 2)

# 绘制最小外接圆并保存相关数据
(x, y), min_enclosing_radius = cv2.minEnclosingCircle(approx)
min_enclosing_center = (int(x), int(y))
min_enclosing_radius = int(min_enclosing_radius)
cv2.circle(src_resized, min_enclosing_center, min_enclosing_radius, (0, 255, 0), 2)

# 保存带轮廓的图像
result_dir = 'result'
if not os.path.exists(result_dir):
    os.makedirs(result_dir)
photo_dir = os.path.join(result_dir, 'photo')
if not os.path.exists(photo_dir):
    os.makedirs(photo_dir)
index = len(os.listdir(photo_dir)) + 1
cv2.imwrite(os.path.join(photo_dir, 'screenshot{}.jpg'.format(index)), src_resized)

# 保存数据至文件
file_dir = os.path.join(result_dir, 'file')
if not os.path.exists(file_dir):
    os.makedirs(file_dir)
data_file_path = os.path.join(file_dir, 'data{}.txt'.format(index))
with open(data_file_path, 'w') as file:
    file.write("Min Enclosing Circle Center(最小外接圆圆心): {}\n".format(min_enclosing_center))
    file.write("Min Enclosing Circle Radius(最小外接圆半径): {}\n".format(min_enclosing_radius))
    file.write("Max Inscribed Circle Center(最大内接圆圆心): {}\n".format(max_loc))
    file.write("Max Inscribed Circle Radius(最大内接圆半径): {}\n".format(max_radius))
    file.write("Polygon Contour Points(多边形轮廓点坐标):\n")
    for point in polygon_points:
        x, y = point
        file.write("    ({}, {})\n".format(x, y))

cv2.imshow('result', src_resized)

cv2.waitKey(0)
cv2.destroyAllWindows()

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值