mask边缘问题脚本

        在使用智能工具标注时,经常会出现边缘部分没有标注上mask区域的情况。会对训练的准确度造成一定程度的影响。
        将mask.PN图片进行膨胀和腐蚀操作后,边角部分的mask区域没有完全补齐,因此再划定两个roi区域,通过比较mask占比来填充。

        下图为将原图和mask区域重合后的图片,可以看到左右两角有黑色区域。(因为没有png的问题图片,用jpg的图片先试试看效果)

import cv2
import numpy as np
import os

# 定义膨胀和腐蚀的核
kernel = np.ones((3, 3), np.uint8)

# PNG格式原始图像路径
image_path = '/home/lxy/Desktop/test/fushi_imgae_test/mask'

# 读取PNG格式的原始图像
images = []
for file in os.listdir(image_path):
    if not file.endswith(".png"):
    # if not file.endswith(".jpg"):
        continue

    image_file = os.path.join(image_path, file)
    if not os.path.exists(image_file):
        continue

    image = cv2.imread(image_file)
    images.append(image)

# 对原始图像进行膨胀和腐蚀操作
processed_images = []
for image in images:
    dilated_image = cv2.dilate(image, kernel, iterations=10)
    eroded_dilated_image = cv2.erode(dilated_image, kernel, iterations=10)
    processed_images.append(eroded_dilated_image)

# 定义ROI区域的坐标
roi1_tl = (0, 400)  # 区域一左上角坐标
roi1_br = (80, 480)  # 区域一右下角坐标
roi2_tl = (560, 400)  # 区域二左上角坐标
roi2_br = (640, 480)  # 区域二右下角坐标

# 在图像上绘制两个ROI区域
for i in range(len(images)):
    processed_images[i] = cv2.rectangle(processed_images[i], roi1_tl, roi1_br, (0, 255, 0), 2)
    processed_images[i] = cv2.rectangle(processed_images[i], roi2_tl, roi2_br, (0, 255, 0), 2)

# 计算mask区域所占比例,并将整个ROI区域划为mask
for i in range(len(images)):
    # 提取ROI区域
    roi1 = processed_images[i][roi1_tl[1]:roi1_br[1], roi1_tl[0]:roi1_br[0]]
    roi2 = processed_images[i][roi2_tl[1]:roi2_br[1], roi2_tl[0]:roi2_br[0]]

    # 计算ROI区域的总像素数量
    total_pixels_roi1 = roi1.shape[0] * roi1.shape[1]
    total_pixels_roi2 = roi2.shape[0] * roi2.shape[1]

    # 计算mask区域的像素数量
    mask_pixels_roi1 = np.count_nonzero(roi1)
    mask_pixels_roi2 = np.count_nonzero(roi2)

    # 计算mask区域所占比例,避免除以零错误
    mask_ratio_roi1 = mask_pixels_roi1 / total_pixels_roi1 if total_pixels_roi1 != 0 else 0
    mask_ratio_roi2 = mask_pixels_roi2 / total_pixels_roi2 if total_pixels_roi2 != 0 else 0

    # 如果mask区域所占比例超过70%,则将整个ROI区域划为mask
    if mask_ratio_roi1 > 0.7:
        processed_images[i][roi1_tl[1]:roi1_br[1], roi1_tl[0]:roi1_br[0]] = 255
    if mask_ratio_roi2 > 0.7:
        processed_images[i][roi2_tl[1]:roi2_br[1], roi2_tl[0]:roi2_br[0]] = 255


# 创建一个蓝色的间隔框
blue_line = np.zeros((processed_images[0].shape[0], 5, 3), dtype=np.uint8)
blue_line[:] = (255, 0, 0)  # 蓝色

# 显示原始图像和处理后的图像
current_index = 0
while True:
    combined_image = np.hstack((images[current_index], blue_line, processed_images[current_index]))
    cv2.imshow('Original vs Processed', combined_image)
    key = cv2.waitKey(0) & 0xFF

    if key == ord('a'):
        current_index = (current_index - 1) % len(images)
    elif key == ord('d'):
        current_index = (current_index + 1) % len(images)
    elif key == 27:  # ESC键
        break

# 关闭所有窗口
cv2.destroyAllWindows()

        结果:

         得到的图片为png格式或jpg格式,如有需要json格式还需要再进行转换。

       附:

        根据labelme.json文件和jpg文件来进行腐蚀和膨胀操作。

import cv2
import numpy as np
import os
import json
from tqdm import tqdm
from PIL import Image, ImageDraw, ImagePath
# 读取原始图像
jpg = '/home/lxy/Desktop/test/fushi_imgae_test/jpg/'
labelme_json = '/home/lxy/Desktop/test/fushi_imgae_test/labelme_json/'

# 遍历 LabelMe 格式的 JSON 文件夹中的所有文件,只处理 JSON 格式的文件
for file in tqdm(os.listdir(labelme_json)):
    if not file.endswith(".json"):
        continue

    # 根据 JSON 文件名生成对应的图像文件名,并检查该图像文件是否存在。
    image_name = file.replace(".json", ".jpg")
    image_file = os.path.join(jpg, image_name)
    if not os.path.exists(image_file):
        continue

    # 读取图像文件
    image = cv2.imread(image_file)
    cv2.imshow('image_file',image)
    # cv2.waitKey(6000)
    # cv2.destroyAllWindows(27)
    mask_img = np.zeros_like(image)

    with open(os.path.join(labelme_json, file), 'r') as f:
        data = f.read()
        # convert str to json objs
        data = json.loads(data)

        # 遍历 JSON 文件中的标注信息,获取标签和边界点
        for idx,d in enumerate(data['shapes']):
            label = d['label']
            points = d['points']
            path = tuple(map(tuple, points))

            # 将边界点连接起来并填充为白色,以创建标注掩码图像
            mask_img = cv2.drawContours(mask_img, [np.array(points)], 0, (255, 255, 255), -1)

            kernel = np.ones((3, 3), np.uint8)  # 定义膨胀的核大小

            # 对标注掩码图像进行腐蚀操作
            eroded_mask_img = cv2.erode(mask_img, kernel, iterations=10)
            # kernel = np.ones((5, 5), np.uint8)  # 定义腐蚀的核大小

            # 对标注掩码图像进行膨胀操作
            dilated_mask_img = cv2.dilate(mask_img, kernel, iterations=10)
            # result = mask_img - eroded_mask_img

            # 先膨胀再腐蚀
            dilated_mask_img = cv2.dilate(mask_img, kernel, iterations=15)
            eroded_dilated_mask_img = cv2.erode(dilated_mask_img, kernel, iterations=10)

            # 计算腐蚀后的区域大小
            gray_img = cv2.cvtColor(eroded_mask_img, cv2.COLOR_BGR2GRAY)
            _, binary_img = cv2.threshold(gray_img, 1, 255, cv2.THRESH_BINARY)
            contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
            area = cv2.contourArea(contours[0])
        
            # 如果区域大小达到 1000,则保留;否则涂黑
            if area >= 1800:
                # 保留标签区域 
                final_img = eroded_mask_img
                border_points = [tuple(point[0]) for point in contours[0]]
                # 输出边界坐标点列表
                # print(border_points)
        
        # 修改标签区域以外的像素的 RGB 值
        for i in range(image.shape[0]):
            for j in range(image.shape[1]):
                if eroded_mask_img[i, j, 0] != 255:
                    # 修改标签区域以外的像素的 RGB 值为你想要的颜色
                    image[i, j] = [0, 0, 0]  # 将像素修改为全黑色

            # 保存结果图像
        cv2.imwrite(jpg+'/'+str(idx)+'mask_img.jpg',mask_img)
        cv2.imwrite(jpg+'/'+str(idx)+'_dilated.jpg', dilated_mask_img)
        cv2.imwrite(jpg+'/'+str(idx)+'_eroded.jpg',eroded_mask_img)
        # 保存经过先膨胀再腐蚀处理的图像
        cv2.imwrite(jpg+'/'+str(idx)+'_eroded_dilated.jpg', eroded_dilated_mask_img)

2024.3.25新增:

import cv2
import numpy as np
import os
import json
from tqdm import tqdm

'''
    读取 LabelMe 格式的 JSON 文件,并根据标注信息创建标注掩码图像
    对标注掩码图像进行膨胀和腐蚀操作
    划定两块roi区域
    在这两块roi区域中 分别求取mask区域所占比例 如果超过70% 则将整个roi区域划为mask
'''


# 读取 LabelMe 格式的 JSON 文件夹和保存标注掩码图像的文件夹
labelme_json_dir = '/home/lxy/Desktop/test/fushi_imgae_test/labelme_json'
mask_output_dir = '/home/lxy/Desktop/test/fushi_imgae_test/mask'

# 定义膨胀和腐蚀的核
kernel = np.ones((3, 3), np.uint8)

# 遍历 LabelMe 格式的 JSON 文件夹中的所有文件,只处理 JSON 格式的文件
for file in os.listdir(labelme_json_dir):
    if not file.endswith(".json"):
        continue

    # 读取 JSON 文件
    with open(os.path.join(labelme_json_dir, file), 'r') as f:
        data = json.load(f)

    # 创建与图像相同大小的空白图像作为标注掩码图像
    mask_img = np.zeros((data['imageHeight'], data['imageWidth']), dtype=np.uint8)

    # 根据 JSON 文件中的标注信息创建标注掩码图像
    for shape in data['shapes']:
        points = np.array(shape['points'], np.int32)
        cv2.fillPoly(mask_img, [points], 255)

    # 对标注掩码图像进行膨胀和腐蚀操作
    dilated_mask_img = cv2.dilate(mask_img, kernel, iterations=1)
    eroded_dilated_mask_img = cv2.erode(dilated_mask_img, kernel, iterations=1)

    # 定义两块 ROI 区域
    roi1_tl = (0, 400)  # 区域一左上角坐标
    roi1_br = (80, 480)  # 区域一右下角坐标
    roi2_tl = (560, 400)  # 区域二左上角坐标
    roi2_br = (640, 480)  # 区域二右下角坐标

    # 计算两块 ROI 区域中 mask 区域所占比例,并根据条件将整个 ROI 区域划为 mask
    mask_ratio_roi1 = np.count_nonzero(eroded_dilated_mask_img[roi1_tl[1]:roi1_br[1], roi1_tl[0]:roi1_br[0]]) / ((roi1_br[1] - roi1_tl[1]) * (roi1_br[0] - roi1_tl[0]))
    mask_ratio_roi2 = np.count_nonzero(eroded_dilated_mask_img[roi2_tl[1]:roi2_br[1], roi2_tl[0]:roi2_br[0]]) / ((roi2_br[1] - roi2_tl[1]) * (roi2_br[0] - roi2_tl[0]))

    if mask_ratio_roi1 > 0.7:
        eroded_dilated_mask_img[roi1_tl[1]:roi1_br[1], roi1_tl[0]:roi1_br[0]] = 255
    if mask_ratio_roi2 > 0.7:
        eroded_dilated_mask_img[roi2_tl[1]:roi2_br[1], roi2_tl[0]:roi2_br[0]] = 255

    # 保存处理后的标注掩码图像
    mask_output_path = os.path.join(mask_output_dir, file.replace('.json', '_mask.png'))
    cv2.imwrite(mask_output_path, eroded_dilated_mask_img)

对新的掩码图像(labelme.png)转回json文件(labelme.json)

import cv2
import numpy as np
import os
import json

# 读取膨胀和腐蚀后的标注掩码图像的文件夹和保存恢复的 LabelMe JSON 文件的文件夹
mask_output_dir = '/home/lxy/Desktop/test/fushi_imgae_test/mask'
restored_json_dir = '/home/lxy/Desktop/test/fushi_imgae_test/picture'

# 遍历膨胀和腐蚀后的标注掩码图像的文件夹中的所有文件
for file in os.listdir(mask_output_dir):
    if not file.endswith("_mask.png"):
        continue

    # 读取标注掩码图像
    mask_img = cv2.imread(os.path.join(mask_output_dir, file), cv2.IMREAD_GRAYSCALE)

    # 创建一个空的 LabelMe 格式 JSON 数据
    labelme_data = {
        "version": "5.0.1",
        "flags": {},
        "shapes": [],
        "imagePath": file.replace('_mask.png', '.png'),
        "imageData": None,
        "imageHeight": mask_img.shape[0],
        "imageWidth": mask_img.shape[1]
    }

    # 根据标注掩码图像恢复标注信息
    contours, _ = cv2.findContours(mask_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for contour in contours:
        shape = {
            "label": "0",
            "points": contour.reshape(-1, 2).tolist(),
            "group_id": None,
            "shape_type": "polygon",
            "flags": {}
        }
        labelme_data["shapes"].append(shape)

    # 保存恢复的 LabelMe JSON 文件
    restored_json_path = os.path.join(restored_json_dir, file.replace('_mask.png', '_restored.json'))
    with open(restored_json_path, 'w') as f:
        json.dump(labelme_data, f, indent=4)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值