图片分割处理(以玉米颗粒的图片分割为例)

news2024/11/18 17:34:15

问题:

为完成玉米颗粒分类任务,现需要处理训练图片,将以下图片中的玉米颗粒进行分割:
在这里插入图片描述
目标:
在这里插入图片描述

操作步骤(完整代码附在最后,该部分为解释说明)

一、提取通道并进行二值化

# 提取蓝色通道
blue_channel = image[:, :, 0]
# 二值化图像
threshold = 150  # 阈值
_, binary_image = cv2.threshold(blue_channel, threshold, 255, cv2.THRESH_BINARY)

结果:
在这里插入图片描述
说明:

1、cv2.threshold()
retval, threshold_image = cv2.threshold(src, thresh, maxval, type[, dst])

参数:
src: 输入的单通道图像。这里是提取的蓝色通道图像。
thresh: 阈值,将像素值分为大于等于阈值和小于阈值的两部分。
maxval: 分类后大于等于阈值的像素值,通常设置为最大值255type: 阈值化的类型,包括以下几种:
cv2.THRESH_BINARY: 如果像素值大于等于阈值,设置为 maxval,否则设置为0。
cv2.THRESH_BINARY_INV: 如果像素值大于等于阈值,设置为0,否则设置为 maxval。
cv2.THRESH_TRUNC: 如果像素值大于等于阈值,保持原始值,否则设置为阈值。
cv2.THRESH_TOZERO: 如果像素值大于等于阈值,保持原始值,否则设置为0。
cv2.THRESH_TOZERO_INV: 如果像素值大于等于阈值,设置为0,否则保持原始值。
dst(可选):输出图像,与输入图像大小和类型相同,通常不需要指定。

返回值:
retval:选择的阈值,通常与输入阈值 thresh 相同,但如果使用自适应阈值化时,可能不同。
threshold_image:阈值化后的图像,是一个与输入图像大小和类型相同的单通道灰度图像。
2、为什么选择提取蓝色通道?

黄色是由红色和绿色混合而成的颜色,因此在RGB颜色模型中,黄色物体在红色通道和绿色通道上都具有较高的强度,而在蓝色通道上的强度较低。提取蓝色通道后,黄色物体通常会变得比背景更暗,从而更容易与背景区分开来,有助于突出玉米颗粒并进行后续的图像处理和分割。
那么怎么判断出这个物体的颜色和哪个通道强度有关呢:可以分别将图像分离成不同的颜色通道(红色、绿色和蓝色),然后可以查看每个通道的图像。

blue_channel = image[:, :, 0]  # 蓝色通道
green_channel = image[:, :, 1]  # 绿色通道
red_channel = image[:, :, 2]  # 红色通道
3、二值化阈值的选择

由于在这个任务中,训练集图像具有一致的背景和物体颜色,因此可以简单地手动选择一个固定的阈值。但如果图片包含了更多场景,可以选择其他的阈值设置方式,如自适应阈值等。

二、反转图像像素值

inverted_image = cv2.bitwise_not(binary_image)

结果:
在这里插入图片描述
说明:

1、cv2.bitwise_not()
result = cv2.bitwise_not(src[, dst[, mask]])

参数:
src:输入图像,可以是单通道或多通道的图像。
dst:输出图像,与输入图像具有相同的大小和通道数。如果未提供,函数会创建一个新的图像来存储结果。
mask:可选参数,用于指定一个掩模,只有掩模中值为非零的像素才会执行位反转操作。
2、为什么要反转图像像素值?

后续使用到的形态学操作和轮廓查找是基于目标区域是白色的前提下进行的,反转操作是为了提高分割的准确性和可靠性。

三、闭运算

# 定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))  # 使用矩形结构元素
# 闭运算
closed_image = cv2.morphologyEx(inverted_image, cv2.MORPH_CLOSE, kernel)

结果:
在这里插入图片描述
说明:

1、cv2.getStructuringElement()
element = cv2.getStructuringElement(shape, ksize[, anchor])

cv2.getStructuringElement 函数是OpenCV库中用于创建图像处理中的结构元素的函数。
结构元素通常用于形态学操作,如腐蚀、膨胀、开运算、闭运算等。
结构元素可以是不同形状的内核,例如矩形、椭圆、十字形等,
用于定义操作的邻域,例如腐蚀和膨胀操作中的探测窗口。

参数:
shape:结构元素的形状,可以是以下之一:
cv2.MORPH_RECT:矩形结构元素
cv2.MORPH_CROSS:十字形结构元素
cv2.MORPH_ELLIPSE:椭圆形结构元素
ksize:结构元素的大小,通常以 (width, height) 或者单个整数值指定。
anchor:可选参数,结构元素的锚点位置,默认为结构元素的中心。

注:结构元素的不同形状和大小可以用于不同的任务和图像处理需求。例如,矩形结构元素通常用于一般形态学操作,椭圆结构元素可以更好地适应曲线或圆形物体的形状,十字形结构元素可用于特定方向的操作,如边缘检测。

2、cv2.morphologyEx()
result = cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])

参数:
src:输入图像,通常是二进制图像(黑白图像)。
op:形态学操作的类型,可以是以下之一:
cv2.MORPH_ERODE:腐蚀操作
cv2.MORPH_DILATE:膨胀操作
cv2.MORPH_OPEN:开运算(先腐蚀后膨胀)
cv2.MORPH_CLOSE:闭运算(先膨胀后腐蚀)
其他高级形态学操作如梯度、礼帽、黑帽等。
kernel:形态学操作的内核(结构元素),用于定义操作的邻域。可以使用 cv2.getStructuringElement 函数创建内核。
dst:可选参数,输出图像,用于存储结果。如果不提供,函数会创建一个新的图像。
anchor:可选参数,内核的锚点位置,默认为内核的中心。
iterations:可选参数,操作的迭代次数,默认为1。
borderType:可选参数,边界处理方式,默认为 cv2.BORDER_CONSTANT。
borderValue:可选参数,当边界处理方式为 cv2.BORDER_CONSTANT 时使用的边界值,默认为0

cv2.morphologyEx()函数根据指定的操作类型 op 和内核 kernel,对输入图像进行操作。
1、腐蚀:缩小白色区域,使物体变小。它将内核滑动到图像上,只有当内核下的所有像素都是白色时,中心像素才保持白色,否则变成黑色。
2、膨胀:扩展白色区域,使物体变大。它将内核滑动到图像上,将内核下的任何白色像素(像素值为255)扩展到中心像素位置,从而使前景区域变大。
3、开运算:先腐蚀后膨胀的组合操作,用于去除小白色噪点或分离物体,平滑物体的边界。
4、闭运算:先膨胀后腐蚀的组合操作,用于关闭物体之间的小孔或连接物体。从结果对比中可以发现小孔面积减小。

四、填充轮廓

# 寻找轮廓
contours, _ = cv2.findContours(closed_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 创建一个空白的二值掩模
mask = np.zeros_like(image[:, :, 0], dtype=np.uint8)
# 填充轮廓
filled_image = cv2.drawContours(mask, contours, -1, (255, 255, 255), thickness=cv2.FILLED)

结果:
在这里插入图片描述
说明:

1、cv2.findContours()
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

参数:
image:输入的二值化图像,通常是一个黑白图像(只包含两个像素值,如0255)。
mode:轮廓检索模式,是一个表示如何检索轮廓的标志。常用的模式包括:
cv2.RETR_EXTERNAL:只检测最外层的轮廓。
cv2.RETR_LIST:检测所有轮廓并将它们存储在列表中,不建立层次关系。
cv2.RETR_CCOMP:检测所有轮廓并将它们存储在两层的层次结构中。
cv2.RETR_TREE:检测所有轮廓并重建一个完整的轮廓层次。
method:轮廓逼近方法,是一个表示如何逼近轮廓的标志。常用的方法包括:
cv2.CHAIN_APPROX_SIMPLE:压缩水平、垂直和对角方向的像素,只保留端点。
cv2.CHAIN_APPROX_TC89_L1:使用 Teh-Chin 近似算法。
cv2.CHAIN_APPROX_TC89_KCOS:使用 Teh-Chin 近似算法的一种改进版本。
contours:返回的轮廓列表,每个轮廓是一个表示对象边界的点的集合。
hierarchy:可选参数,返回的轮廓层次结构信息。在某些情况下,可以用于分析轮廓之间的关系。
offset:可选参数,轮廓点坐标的偏移量。

返回值:
contours:包含检测到的轮廓的列表,每个轮廓是一个点的集合。
hierarchy:包含轮廓层次结构信息的列表。
2、二值掩膜

在图像处理中,二值掩膜是一种用于标记图像中某些区域的图像,通常是黑白图像,其中白色像素表示感兴趣的区域,而黑色像素表示不感兴趣的区域。它是一种用于遮罩或选择特定图像区域的工具。

np.zeros_like(image[:, :, 0], dtype=np.uint8)

这个操作的目的是创建一个黑色背景的图像:
以输入图像 image 中的一个通道(通常是蓝色通道,即 image[:, :, 0])作为模板,
创建一个与模板图像具有相同形状的全零图像,其中所有像素值都初始化为零。
使用 dtype=np.uint8 指定了像素值的数据类型为无符号8位整数,即像素值的范围在 0255 之间。

这个全零图像用作后续的轮廓填充操作的目标图像,轮廓填充会将感兴趣的区域标记为白色(255),而不感兴趣的区域保持黑色(0)。

3、cv2.drawContours()
cv2.drawContours(image, contours, contourIdx, color, thickness, lineType, hierarchy, maxLevel, offset)

参数:
image: 要在其上绘制轮廓的图像。
contours: 要绘制的轮廓,通常是通过 cv2.findContours 函数获得的轮廓列表。
contourIdx: 要绘制的轮廓的索引,如果为负数,将绘制所有轮廓。
color: 绘制轮廓的颜色,通常是一个三元组 (B, G, R),其中 B、G、R 分别表示蓝色、绿色和红色的颜色通道值。可以用 (0, 255, 0) 表示绿色。
thickness: 绘制轮廓线的厚度,如果设置为负数或 cv2.FILLED,则填充轮廓内部。
lineType: 线的类型,通常使用默认值 8。
hierarchy: 轮廓的层次信息,通常不需要手动指定。
maxLevel: 最大层次级别,通常使用默认值 0。
offset: 绘制轮廓时的偏移,通常使用默认值 (0, 0)

补充:

在以上步骤处理的基础上,我们会遍历得到的轮廓列表,对图片进行剪裁,由于闭运算之后的图片会存在白色噪点,因此它们也会加入到轮廓列表中,因此,我们需要设置面积阈值,筛选掉小面积的轮廓。但可以发现,文章最开头的输出仍包含一张与待测目标物体无关的corn_0.jpg图。
在这里插入图片描述
为了解决这个问题,我们需要尽可能地减少白色早点的产生,意味着我们需要做进一步的腐蚀操作,将白色噪点去掉。为了减小腐蚀带来的目标物体的信息丢失,在腐蚀后再进行膨胀操作,扩大目标物体的区域范围。因此我们再次进行开运算。

# 闭运算
closed_image = cv2.morphologyEx(inverted_image, cv2.MORPH_CLOSE, kernel)
#开运算
closed_image2 = cv2.morphologyEx(closed_image, cv2.MORPH_OPEN, kernel)
# 寻找轮廓
contours, _ = cv2.findContours(closed_image2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

结果:
在这里插入图片描述
增加开运算后的分割效果:
在这里插入图片描述

完整代码

import os
import time

import cv2
import numpy as np

def crop_corn():
    # 确保 "output" 文件夹存在
    output_folder = "output_p"
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 加载图像
    image = cv2.imread("./input_p/image.jpg")

    # 提取蓝色通道
    blue_channel = image[:, :, 0]

    # 二值化图像
    threshold = 150  # 阈值
    _, binary_image = cv2.threshold(blue_channel, threshold, 255, cv2.THRESH_BINARY)

    # 反转图像像素值
    inverted_image = cv2.bitwise_not(binary_image)

    # 定义结构元素
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))  # 使用矩形结构元素

    # 闭运算
    closed_image = cv2.morphologyEx(inverted_image, cv2.MORPH_CLOSE, kernel)
    #开运算
    closed_image2 = cv2.morphologyEx(closed_image, cv2.MORPH_OPEN, kernel)

    # 寻找轮廓
    contours, _ = cv2.findContours(closed_image2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 创建一个空白的二值掩模
    mask = np.zeros_like(image[:, :, 0], dtype=np.uint8)
    # 填充轮廓
    filled_image = cv2.drawContours(mask, contours, -1, (255, 255, 255), thickness=cv2.FILLED)
    cv2.imwrite("filled_image.jpg",filled_image)
    # 寻找填充后的轮廓
    filled_contours, _ = cv2.findContours(filled_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 根据轮廓进行剪裁
    corn_images = []
    for contour in filled_contours:
        area = cv2.contourArea(contour)
        if area > 1000:  # 设置面积阈值,筛选掉小面积的轮廓
            x, y, w, h = cv2.boundingRect(contour)
            corn_image = image[y:y+h, x:x+w]
            corn_images.append(corn_image)

    # 保存剪裁下来的玉米颗粒
    for i, corn_image in enumerate(corn_images):
        # cv2.imwrite(f"corn_{i}.jpg", corn_image)  # 保存剪切下来的玉米颗粒图像
        output_filename = f"corn_{i}.jpg"
        output_path = os.path.join(output_folder, output_filename)
        cv2.imwrite(output_path, corn_image)

if __name__ == "__main__":
    crop_corn()

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

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

相关文章

CCC数字钥匙设计【BLE】 --建立安全测距

1、建立安全测距Establish Secure Ranging 车端总共有三种建立安全测距的方式,具体如下: 1) Optimal Flow 2) Sub-Optimal Flow 3) Ranging Recovery Flow 为了确定建立安全测距需要执行哪条流程,车辆需要进行以下流程选择。当车辆和设备…

速码!!BGP最全学习笔记:BGP路径属性与选路原则

BGP路径属性 1、路径属性分类 公认属性:所有BGP路由器都必须能够识别的属性 公认必遵(Well-known Mandatory):必须包括在每个Update消息里。公认任意(Well-known Discretionary):可能包括在某…

数学公式测试

MVP变换 MVP变换用来描述视图变换的任务,即将虚拟世界中的三维物体映射(变换)到二维坐标中。 MVP变换分为三步: 模型变换(model tranformation):将模型空间转换到世界空间(找个好的地方,把所…

4年北漂之路,从软件测试外包到外企的一点小心得

4年前,我独自一人拖着行李箱来到了北京,成为了一名北漂,离开了校园的庇护,只身一人想要在这片陌生的地方闯出一番名堂,可最后却不得人意,面临着和所有北漂群体的共同困局,没有任何归属感&#x…

【Python Fastapi】js上传文件,fastapi处理,js显示回传信息

python from fastapi import FastAPI, File, UploadFile, HTTPException from fastapi.staticfiles import StaticFiles from fastapi.responses import HTMLResponse from typing import List import requestsapp FastAPI()# 配置静态文件目录 app.mount("/static"…

C++程序员,想入坑音视频方向,需要掌握那些技能树?

C程序员,想入坑音视频方向,需要掌握那些技能树? “音视频”方向太笼统了。 最核心的技术包括编码理论,从基础开始就是信号处理,傅里叶变换,DCT, 采样量化插值等等。这些和C没啥关系,就是一套数学理论。 …

工作薄代码之将活动工作表复制到新工作簿等

【分享成果,随喜正能量】得失,可以说是人类事业上的考验,不要因一时的得失影响一生的期许。得失是一时的,理想是一生的。。 我给VBA下的定义:VBA是个人小型自动化处理的有效工具。可以大大提高自己的劳动效率&#xf…

基于SpringBoot的企业客户管理系统

目录 前言 一、技术栈 二、系统功能介绍 管理员功能模块 员工功能模块 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 本论文主要论述了如何使用JAVA语言开发一个企业客户管理系统,本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c…

JVM堆内存转储

堆转储是 JVM 中特定时刻内存中的所有对象的快照。它们对于解决内存泄漏问题并优化 Java 应用程序中的内存使用情况非常有用。 堆转储通常以二进制格式 hprof 文件存储。我们可以使用 jhat 或 JVisualVM 等工具打开和分析这些文件。 下面介绍两种堆转储的方式: 1…

HTTP 请求轻松搞定:Swift 网络编程的不二之选 | 开源日报 No.38

Alamofire/Alamofire Stars: 39.8k License: MIT Alamofire 是一个用 Swift 编写的 HTTP 网络库。 简洁的语法和强大的功能集,让你仅需几行代码就能实现诸如自动重试等强大特性。支持链式请求/响应方法,使得处理网络请求变得如丝般顺滑。完美兼容 Swif…

前端性能测试工具-lighthouse

Lighthouse简介 Lighthouse 是 Google 的一款开源工具,它可以作为一个 Chrome 扩展程序运行,或从命令行运行。只需要给 Lighthouse 提供一个要审查的网址,它将针对此页面运行一连串的测试,然后生成一个页面性能的报告。 Lightho…

【电子通识】办法总比问题多:立式贴片座子整形成卧式

最近在测试一些和电池有关的项目,因为这个电池接口是没有用过的,以前做的一些接口板上没有兼容,导致不方便测试。 拿到座子后发现这个座子是立式贴片的。 但是不方便我做测试接口板工装,因为已经有一个立工座子了,再焊…

多个pdf合并成一个文件,3个方法合并pdf

如何把多个pdf合并成一个文件?在我们日常的工作中,经常会遇到一些需要处理的文件,其中包括PDF文件。特别是当我们需要将多个PDF文件合并成一个PDF文件时,会面临一些困难。这样的情况下,我们的阅读能力会受到限制&#…

ElementUI之首页导航+左侧菜单

一.Mockjs 什么是Mock.js Mock.js的优缺点 安装配置Mock.js 引入jsdev.env.js ​编辑 引入 prod.env.js 导依赖 导入json数据 造数据 测试结果 ​编辑 二. 总线 什么是总线 导入组件 编写路由 跳转主页 编写AppMain 编写LeftNav 编写TopNav 一.Mockjs 什么是Moc…

车载通信架构 —— SOME/IP-SD 协议介绍

车载通信架构 —— SOME/IP-SD 协议介绍 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗…

Xilinx FPGA 7系列 GTX/GTH Transceivers (3) Aurora 8b10b

第一节:Xilinx FPGA 7系列 GTX/GTH Transceivers (1)–了解了GTX硬件的基础知识 第二节:IBERT GTX --通过Ibert IP测试链路通信 学习官方历程 aurora 8b10b single lane 4byte 1硬件介绍 2 实验目标 跑通官方历程。检测发送数据与接收收据一致。 3 IP 生成过程 在 IP Cat…

Xcode14.3.1打包报错Command PhaseScriptExecution failed with a nonzero exit code

真机运行编译正常,一打包就报错 rsync error: some files could not be transferred (code 23) at /AppleInternal/Library/BuildRoots/d9889869-120b-11ee-b796-7a03568b17ac/Library/Caches/com.apple.xbs/Sources/rsync/rsync/main.c(996) [sender2.6.9] Command PhaseScrip…

@NotNull注解不生效,全局异常处理

1.引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>3.1.2</version> </dependency> 2&#xff1a;实体类 实体类属性加上NotNull注解…

第二章 使用matplotlib绘制简单图表

第二章 使用matplotlib绘制简单图表 1.绘制折线图 1.1.使用plot()绘制折线图 ​ 使用pyplot的plot()函数可以快速绘制折线图。plot()函数的语法格式如下&#xff1a; plot&#xff08;x, y, fmt, scalexTrue, scaleyTrue, dataNone, labelNone, *args, **kwargs&#xff09…

开启 Kerberos 安全认证的大数据环境中如何正确指定 HS2 的 jdbc url 地址?

开启 Kerberos 安全认证的大数据环境中如何正确指定 HS2 的 jdbc url 地址&#xff1f; 1 Kerberos 环境中 HS2 的认证方式概述 大家知道&#xff0c;HIVE 的认证方式可以通过参数 hive.server2.authentication 在服务端进行统一配置&#xff0c;而在开启了 Kerberos 安全认证…