手把手教你用Python和OpenCV搭建一个半自动标注工具(详细步骤 + 源码)

news2024/11/18 7:51:39

导  读

    本文将手把手教你用Python和OpenCV搭建一个半自动标注工具(包含详细步骤 + 源码)。

背景介绍

    样本标注是深度学习项目中最关键的部分,甚至在模型学习效果上起决定性作用。但是,标注工作往往非常繁琐且耗时。一种解决方案是使用自动图像标注工具,它可以大大减少标注的时间。

    本文主要介绍的半自动标注工具为pyOpenAnnotate,此工具是基于Python和OpenCV实现,最新版本为0.4.0,可通过下面指令安装使用:

pip install pyOpenAnnotate

    详细介绍与使用步骤参考链接:

https://pypi.org/project/pyOpenAnnotate/

    标注效果:

    效果如上图所示,标注完成后可以生成标注文件,后面部分将详细介绍其实现步骤。

      

实现步骤

    实现原理流程:

    说明:

   【1】Threshold(二值化)只接受单通道图像,但这里并不是直接使用灰度转换图来处理,而是从灰度图、R、G、B、H、S、V通道图像中找到对比度最高的图像来做二值化。

   【2】二值化之后并不能保证总是得到我们需要的掩码,有时会有噪声、斑点、边缘的干扰,所以加入了膨胀、腐蚀等形态学处理。

   【3】最后通过轮廓分析得到对象的边界框,也就是左上角和右下角坐标。

      

代码讲解与演示

    首先需要导入所需库:

import cv2import numpy as npimport matplotlib.pyplot as pltplt.rcParams['image.cmap'] = 'gray'

    加载图像:

stags = cv2.imread('stags.jpg')boars = cv2.imread('boar.jpg')berries = cv2.imread('strawberries.jpg')fishes = cv2.imread('fishes.jpg')coins = cv2.imread('coins.png')boxes = cv2.imread('boxes2.jpg')

    选择色彩空间(这里添加了 RGB和HSV,存储在字典中,方便验证使用):​​​​​​​

def select_colorsp(img, colorsp='gray'):    # Convert to grayscale.    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    # Split BGR.    red, green, blue = cv2.split(img)    # Convert to HSV.    im_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)    # Split HSV.    hue, sat, val = cv2.split(im_hsv)    # Store channels in a dict.    channels = {'gray':gray, 'red':red, 'green':green,                 'blue':blue, 'hue':hue, 'sat':sat, 'val':val}         return channels[colorsp]

    显示 1×2 图像的实用函数(display()函数接受两个图像并并排绘制。可选参数是绘图的标题和图形大小):​​​​​​​

def display(im_left, im_right, name_l='Left', name_r='Right', figsize=(10,7)):         # Flip channels for display if RGB as matplotlib requires RGB.    im_l_dis = im_left[...,::-1]  if len(im_left.shape) > 2 else im_left    im_r_dis = im_right[...,::-1] if len(im_right.shape) > 2 else im_right         plt.figure(figsize=figsize)    plt.subplot(121); plt.imshow(im_l_dis);    plt.title(name_l); plt.axis(False);    plt.subplot(122); plt.imshow(im_r_dis);    plt.title(name_r); plt.axis(False);

    阈值处理(thresh()函数接受1通道灰度图像,默认阈值设置为 127。执行逆阈值处理,方便轮廓分析,它返回单通道阈值图像):​​​​​​​

def threshold(img, thresh=127, mode='inverse'):    im = img.copy()         if mode == 'direct':        thresh_mode = cv2.THRESH_BINARY    else:        thresh_mode = cv2.THRESH_BINARY_INV         ret, thresh = cv2.threshold(im, thresh, 255, thresh_mode)             return thresh

      

实例:雄鹿红外图像标注

    整体实现步骤:

  【1】选择色彩空间​​​​​​​

# Select colorspace.gray_stags = select_colorsp(stags)# Perform thresholding.thresh_stags = threshold(gray_stags, thresh=110)  # Display.display(stags, thresh_stags,         name_l='Stags original infrared',         name_r='Thresholded Stags',        figsize=(20,14))

  【2】执行阈值

  【3】执行形态学操作​​​​​​​

def morph_op(img, mode='open', ksize=5, iterations=1):    im = img.copy()    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(ksize, ksize))         if mode == 'open':        morphed = cv2.morphologyEx(im, cv2.MORPH_OPEN, kernel)    elif mode == 'close':        morphed = cv2.morphologyEx(im, cv2.MORPH_CLOSE, kernel)    elif mode == 'erode':        morphed = cv2.erode(im, kernel)    else:        morphed = cv2.dilate(im, kernel)         return morphed​​​​​​​
# Perform morphological operation.morphed_stags = morph_op(thresh_stags) # Display.display(thresh_stags, morphed_stags,         name_l='Thresholded Stags',         name_r='Morphological Operations Result',        figsize=(20,14))

  【4】轮廓分析以找到边界框​​​​​​​

bboxes = get_bboxes(morphed_stags)ann_morphed_stags = draw_annotations(stags, bboxes, thickness=5, color=(0,0,255)) # Display.display(ann_stags, ann_morphed_stags,         name_l='Annotating Thresholded Stags',         name_r='Annotating Morphed Stags',        figsize=(20,14))

  【5】过滤不需要的轮廓​​​​​​​

def get_filtered_bboxes(img, min_area_ratio=0.001):    contours, hierarchy = cv2.findContours(img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)    # Sort the contours according to area, larger to smaller.    sorted_cnt = sorted(contours, key=cv2.contourArea, reverse = True)    # Remove max area, outermost contour.    sorted_cnt.remove(sorted_cnt[0])    # Container to store filtered bboxes.    bboxes = []    # Image area.    im_area = img.shape[0] * img.shape[1]    for cnt in sorted_cnt:        x,y,w,h = cv2.boundingRect(cnt)        cnt_area = w * h        # Remove very small detections.        if cnt_area > min_area_ratio * im_area:            bboxes.append((x, y, x+w, y+h))    return bboxes

  【6】绘制边界框​​​​​​​

bboxes = get_filtered_bboxes(thresh_stags, min_area_ratio=0.001)filtered_ann_stags = draw_annotations(stags, bboxes, thickness=5, color=(0,0,255)) # Display.display(ann_stags, filtered_ann_stags,         name_l='Annotating Thresholded Stags',         name_r='Annotation After Filtering Smaller Boxes',        figsize=(20,14))

    视频标注:

  【7】以需要的格式保存

    Pascal VOC、YOLO和COCO 是对象检测中使用的三种流行注释格式。让我们研究一下它们的结构。

    I. Pascal VOC 以 XML 格式存储注释

    II. YOLO标注结果保存在文本文件中。对于每个边界框,它看起来如下所示。这些值相对于图像的高度和宽度进行了归一化。

0 0.0123 0.2345 0.123 0.754
<object-class> <x_centre_norm> <y_centre_norm> <box_width_norm> <box_height_norm>

    让边界框的左上角和右下角坐标表示为(x1, y1)和(x2, y2)。然后:

    III. MS COCO

    这里以YOLO Darknet保存格式为例(当然,你可以保存其他格式):​​​​​​​

def save_annotations(img, bboxes):    img_height = img.shape[0]    img_width = img.shape[1]    with open('image.txt', 'w') as f:        for box in boxes:            x1, y1 = box[0], box[1]            x2, y2 = box[2], box[3]                         if x1 > x2:                x1, x2 = x2, x1            if y1 > y2:                y1, y2 = y2, y1                             width = x2 - x1            height = y2 - y1            x_centre, y_centre = int(width/2), int(height/2)             norm_xc = x_centre/img_width            norm_yc = y_centre/img_height            norm_width = width/img_width            norm_height = height/img_height             yolo_annotations = ['0', ' ' + str(norm_xc),                                 ' ' + str(norm_yc),                                 ' ' + str(norm_width),                                 ' ' + str(norm_height), '\n']                         f.writelines(yolo_annotations)

    标注结果显示与保存:

    简单演示:

—THE END—

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/133556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【苹果家庭群发推】创作AppleScript脚本来控制MacOS附有的iMessage客户端停止考据,近似于组iMessage

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

ENVI_IDL:如何对文件名的日期进行格式化输出?

目录 00 前言 01 第一步&#xff0c;使用file_basename()函数路径中的获取文件名 02 第二步&#xff0c;使用strmid()函数获取文件名的日期 03 第三步&#xff0c;将获取的日期进行类型转换 04 第四步&#xff0c;将日期进行整理 05 第五步&#xff0c;进行格式化输出 …

BiSeNetv2:语义分割经典方法BiSeNet的升级版本

分享IJCV2021上发表的一篇文章BiSeNetv2&#xff0c;这是BiSeNet的升级版本。开源代码地址&#xff1a;https://github.com/open-mmlab/mmsegmentation/tree/master/configs/bisenetv2 1.动机 语义分割是指为每个像素分配一个标签&#xff0c;它广泛用于场景理解、自动驾驶、人…

uniapp中app真机模拟以及小程序编译后css样式异常失效问题原因及解决方案

前言 最近写使用uniapp写app&#xff0c;开发的时候写样式都是使用浏览器h5进行调试一切正常&#xff0c;但是最后进行手机真机调试的时候css样式出现了异常&#xff0c;本文归纳常见的问题 比如在h5页面显示正常&#xff1a; 但是在真机调试app的实现则显示&#xff1a; H5正…

【PyTorch深度学习实践】02_梯度下降

文章目录梯度下降1.梯度下降算法实现代码2.随机梯度下降实现代码3.小批量随机梯度下降梯度下降 1.梯度下降算法 之前可以使用穷举的方法逐个测试找使损失函数最小的点&#xff0c;但当数据过多时&#xff0c;维度过高&#xff0c;会使穷举变得非常困难&#xff0c;因此需要优…

K8s 数据管理

目录前言一、Volume1.1 emptyDir1.1.1 基本概念1.1.2 应用案例1.2 hostPath1.2.1 基本概念1.2.2 应用案例1.3 外部 Storage Provider二、Persistent Volume2.1 基本概念2.1.1 PersistentVolume2.1.2 PersistentVolumeClaim2.2 NFS PersistentVolume前言 与 Docker 类似&#x…

QML教程(一)基础语法

目录 一、导入 二、对象声明 三、对象属性 1.声明对象属性 2.信号属性 3.方法属性 4.附加属性略 5.枚举属性 6.对象属性赋值 四、自定义对象 一、导入 模块导入 语法&#xff1a; import <ModuleIdentifier> [<Version.Number>] [as <Qualifier>…

面向对象设计原则概述

面向对象设计原则概述 软件的可维护性和可复用性 软件工程和建模大师Peter coad认为&#xff0c;一个好的系统设计与应该具备如下三个性质 可扩展性 灵活性 可插入性 软件的可维护性和可复用性 软件的复用和重用拥有众多优点&#xff0c;如可以提高软件的开发效率&#xf…

Educational Codeforces Round 92 (Rated for Div. 2) B. Array Walk

翻译&#xff1a; 给定一个数组&#x1d44e;1&#xff0c;&#x1d44e;2&#xff0c;…&#xff0c;&#x1d44e;&#x1d45b;&#xff0c;由&#x1d45b;个正整数组成。 最初&#xff0c;您位于索引1&#xff0c;分数等于&#x1d44e;1。你可以执行两种动作: 向右移动…

CDN

CDN——Content Delivery Network&#xff0c;内容分发网络。 具体来说&#xff0c;CDN就是采用更多的缓存服务器&#xff08;CDN边缘节点&#xff09;&#xff0c;布放在用户访问相对集中的地区或网络中。当用户访问网站时&#xff0c;利用全局负载技术&#xff0c;将用户的访…

【CSP】邻域均值

邻域均值 邻域均值 题意比较好理解&#xff0c;就是算一些数字。如果采用暴力方法的话&#xff0c;就是用一个边长为 2∗r12*r12∗r1 的正方形框框住大矩阵&#xff0c;然后遍历这个框&#xff0c;求出其平均值&#xff0c;然后移动正方形框&#xff0c;直到大矩阵内所有像…

【免费开放源码】审批类小程序项目实战(预约审批端)

第一节&#xff1a;什么构成了微信小程序、创建一个自己的小程序 第二节&#xff1a;微信开发者工具使用教程 第三节&#xff1a;深入了解并掌握小程序核心组件 第四节&#xff1a;初始化云函数和数据库 第五节&#xff1a;云数据库的增删改查 第六节&#xff1a;项目大纲以及制…

6.5 特殊用途语言特性

文章目录默认实参使用默认实参调用函数默认实参声明默认实参初始值内联函数和constexpr函数内联函数constexpr 函数把内联函数和constexpr函数声明在头文件内调试帮助assert预处理宏NDEBUG预处理变量默认实参 某些函数有这样一种形参,在函数的很多次调用中它们都被赋予一个相同…

电子游戏销售之缺失值检测与处理

电子游戏销售之缺失值检测与处理 文章目录电子游戏销售之缺失值检测与处理0、写在前面1、数据缺失值预处理1.1 表的形状1.2 原始数据每个特征缺失和非缺失的数目1.3 每个特征缺失的率1.4 处理后各特征缺失值的数目1.5 删除缺失值后的数据展示2、替换法处理缺失值2.1 替换法2.2 …

1.Springboot配置细节

一、参考资料 13-SpringBoot配置-项目外部配置加载顺序_哔哩哔哩_bilibili 二、配置 2.1 配置文件 注意变量后面是:&#xff0c;而不是等号 2.2 读取配置文件 2.2.1 Value 比如配置文件application.properities中定义了一个name&#xff0c;其值为abc。 代码里面只需按照如…

一、软件安装与配置

一、PyTorch环境软件安装与配置 1.安装anaconda参考 anaconda老版本下载方法&#xff08;如何查看anaconda与python版本对应关系&#xff09;及安装教程_breadth_的博客-CSDN博客_anaconda旧版本下载 2.在anconda下安装和激活pytorch环境 此步并没有下载pytorch 3.下载pyto…

云计算运营—03 KVM虚拟化技术方案介绍

KVM虚拟化技术方案介绍 1.背景介绍 KVM&#xff08;Kernel-based Virtual Machine&#xff09; 开源全虚拟化方案 支持体系结构 x86(32位,64位)、IA64、PowerPC、S390 依赖x86硬件支持&#xff1a;Intel VT-x/ AMD-V内核模块&#xff0c;使得linux内核成为hypervisor XEN架构 …

《B-树》

tips&#xff1a;B-树读成b树&#xff0c;并不是b减树 【一】基本搜索结构 种类数据格式时间复杂度顺序查找无要求O(N)二分查找有序O(log2N)二叉搜索树无要求O(N)二叉平衡树&#xff08;AVL和红黑树&#xff09;无要求&#xff0c;最后随机O(log2N)哈希无要求O(1)位图无要求O…

linux系统中SPI驱动框架的基本原理与实现

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何使用linux系统中SPI驱动ICM-20608六轴传感器的操作。 目录 第一&#xff1a;linux系统下SPI驱动框架简介 第二&#xff1a;SPI设备驱动编写 第三&#xff1a;SPI设备和驱动匹配过程 第一&#xff1a;linux系统下SPI驱…

MySQL数据库高级面试题(1)

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java面试题…