图像分割方法与问题思考

news/2025/2/19 13:13:15/

前言

图像分割就是预测图像中每一个像素所属的类别或者物体。图像分割有两个子问题,一个是只预测类别层面的分割,对每个像素标出一个位置。第二个是区分不同物体的个体。应用场景,比如自动驾驶,3D 地图重建,美化图片,人脸建模等等。 传统的图像分割通常和图像分类结合,它是图像识别的第一阶段。

图1 图像识别流程

1、图像分割难点:

  • 噪声影响

  • 无法控制环境

  • 没有一致的标准

  • 没有足够的检测数据

  • 存在病态问题

当图像背景中存在与前景目标相 同或相似区域时,没有用户的交互,自动分割出感兴趣的前景目标这个问题本身就是病态的。 图像分割可以分为两类:

  • 完全分割

  • 每部分都和一个实物相关

  • 没有重叠的区域

  • 部分分割

  • 拥有均匀亮度、颜色等的区域

  • 重叠的部分,需要进一步处理

2、分割方法

(1)基于阈值的分割

阈值分割是基于直方图的,对图像进行灰度阈值化是最简单的分割处理。图像阈值化算法简单高效,在很多场景中依然得到很多应用,实时性很好。图像阈值化的缺陷也是明显的,不能够很好的利用图像中的诸如色彩、纹理等语义信息,因此在复杂场景中无法得到目标结果。

图像阈值化分为全局阈值和局部阈值及动态阈值。全局阈值是对整幅图像使用单个阈值,局部阈值是根据图像局部信息在局部执行阈值化。阈值化操作有许多改进算法,例如:局部阈值化、带阈值化、半阈值化、多阈值化等。阈值化的关键在于如何选择阈值。

阈值分割的优点是计算简单、运算效率较高、速度快。全局阈值对于灰度相差很大的不同目标和背景能进行有效的分割。当图像的灰度差异不明显或不同目标的灰度值范围有重叠时,应采用局部阈值或动态阈值分割法。另一方面,这种方法只考虑像素本身的灰度值,一般不考虑空间特征,因而对噪声很敏感。在实际应用中,阈值法通常与其他方法结合使用。

  • 全局阈值

全局阈值法采用同一个灰度值作为分割门限对整幅图进行处理,特别对直方图分布呈双峰态的图像分割效果好,如:

但在有意义的全局阈值不存在的情况下,全局阈值的分割效果很差,如:

  • 迭代阈值图像分割

迭代阈值的步骤为:

  1. 统计图像灰度直方图,求出图象的最大灰度值和最小灰度值,分别记为,令初始阈值

  1. 根据阈值TK将图象分割为前景和背景,计算小于TO所有灰度的均值ZO,和大于TO的所有灰度的均值ZB。

  1. 求出新阈值TK+1=(ZO+ZB)/2;

  1. 若TK==TK+1,则所得即为阈值;否则转2,迭代计算。

动态阈值

(2)边缘检测

边缘检测算法是指利用灰度值的不连续性质,以灰度突变为基础分割出目标区域。对铝铸件表面进行成像后会产生一些带缺陷的区域,这些区域的灰度值比较低,与背景图像相比在灰度上会有突变,这是由于这些区域对光线产生散射所引起的。因此边缘检测算子可以用来对特征的提取。

#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>#include<iostream>using namespace std;
using namespace cv;
Mat roberts(Mat srcImage);
int main(int argc, char** argv)
{Mat src,src_binary,src_gray;src = imread("D:img.jpg");imshow("原图", src);cvtColor(src, src_gray, COLOR_BGR2GRAY);GaussianBlur(src_gray, src_binary, Size(3, 3),0, 0, BORDER_DEFAULT);Mat dstImage = roberts(src_binary);imshow("dstImage", dstImage);waitKey(0);return 0;
}
//roberts 边缘检测Mat roberts(Mat srcImage)
{Mat dstImage = srcImage.clone();int nRows = dstImage.rows;int nCols = dstImage.cols;for (int i = 0; i < nRows - 1; i++) {for (int j = 0; j < nCols - 1; j++) {//根据公式计算int t1 = (srcImage.at<uchar>(i, j) -srcImage.at<uchar>(i + 1, j + 1))*(srcImage.at<uchar>(i, j) -srcImage.at<uchar>(i + 1, j + 1));int t2 = (srcImage.at<uchar>(i + 1, j) -srcImage.at<uchar>(i, j + 1))*(srcImage.at<uchar>(i + 1, j) -srcImage.at<uchar>(i, j + 1));//计算g(x,y)dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);}}return dstImage;

(3)基于颜色空间的分割

在最常见的颜色空间RGB(红、绿、蓝)中,颜色以其红、绿、蓝三种成分表示。在更专业的术语中,RGB将颜色描述为三个成分的元组。每个组件可以取0到255之间的值,其中元组(0,0,0)表示黑色,(255,255,255)表示白色。

RGB是五种主要颜色空间模型之一,每种模型都有许多分支。有这么多颜色空间,因为不同的颜色空间对于不同的目的是有用的。

在印刷领域,CMYK非常有用,因为它描述了从白色背景产生颜色所需的颜色组合。RGB中的0元组是黑色的,而CMYK中的0元组是白色的。我们的打印机包含青色、品红色、黄色和黑色墨盒。

在某些类型的医疗领域,装有染色组织样本的载玻片被扫描并保存为图像。它们可以在HED空间中进行分析,HED空间是应用于原始组织的染色类型——苏木精、曙红和DAB——饱和度的表示。

HSVHSL是色调、饱和度和亮度的描述,对于识别图像中的对比度特别有用。这些颜色空间经常用于软件和网页设计中的颜色选择工具。

实际上,颜色是一个连续的现象,意味着有无限多的颜色。然而,颜色空间通过离散结构(固定数量的整数数值)来表示颜色,这是可以接受的,因为人眼和感知也是有限的。颜色空间完全能够代表我们能够区分的所有颜色。

3、问题引申

若通过上述的分割方法,得到了一幅图像的分割结果,如下图所示:

这里我用不同颜色标记不同的分割体。我想得到该图像的边缘,类似下图,请问有什么好的方法。

cv.findContours的输入只能是二值影像,这样并不能进行边缘的提取。请问有没有小伙伴有比较好的方法呢?


http://www.ppmy.cn/news/23742.html

相关文章

FPGA纯verilog代码实现图像对数变换,提供工程源码和技术支持

目录1、图像对数变换理论2、log系数的matlab生成3、FPGA实现图像对数变换4、vivado与matlab联合仿真5、vivado工程介绍6、上板调试验证并演示7、福利&#xff1a;工程代码的获取1、图像对数变换理论 对数变换可以将图像的低灰度值部分扩展&#xff0c;显示出低灰度部分更多的细…

自动驾驶环境感知——视觉传感器技术

文章目录1. 摄像头的成像原理1.1 单目视觉传感器的硬件结构1.2 单目视觉的成像原理 –小孔成像模型1.3 单目视觉的成像原理 – 像素坐标系1.4 单目视觉三维坐标系转换 – 外参1.5 单目视觉的坐标系转换 – 从世界坐标点到像素坐标1.6 单目视觉的特性2. 视觉传感器的标定2.1 视觉…

3.Linux编程-makefile

makefile文件中定义了一系列的规则来指定, 哪些文件需要先编译, 哪些文件需要后编译, 哪些文件需要重新编译, 甚至于进行更复杂的功能操作, 因为makefile就像一个Shell脚本一样, 其中也可以执行操作系统的命令. makefile带来的好处就是——“自动化编译”, 一旦写好, 只需要一个…

SparkSQL 核心编程

文章目录SparkSQL 核心编程1、新的起点2、SQL 语法1) 读取 json 文件创建 DataFrame2) 对 DataFrame 创建一个临时表3) 通过SQL语句实现查询全表3、DSL 语法1) 创建一个DataFrame2) 查看DataFrame的Schema信息3) 只查看"username"列数据4) 查看"username"列…

初阶指针C

&#x1f680;&#x1f680;&#x1f680;大家觉不错的话&#xff0c;就恳求大家点点关注&#xff0c;点点小爱心&#xff0c;指点指点&#x1f680;&#x1f680;&#x1f680; 目录 &#x1f430;指针是什么 &#x1f430;指针和指针类型 &#x1f338;指针-整数 &#x…

程序环境--翻译+执行

ANSI C标准下&#xff0c;有两种程序环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。 翻译环境包括&#xff1a;预处理&#xff08;预编译&#xff09;编译汇编链接。四个步骤。 第2种是执行/运行环境&#xff0c;它用于实际执行代码。 链接…

【PyTorch】教程:Transfer learning

Transfer learning 实际工作中&#xff0c;只有很少的人从头开始训练 CNN&#xff0c;因为很难获得大量的样本。一般情况下&#xff0c;会通过调用预训练模型&#xff0c;例如 ConvNet 在 ImageNet&#xff08;1.2 M 图像 1000 个类别&#xff09;,可以用 ConvNet 初始化&#…

每日go语言面试题一

1.Redis Multi实现原理 redis中的multi是为了实现redis独特的事务而存在的&#xff0c;底层是有一个队列&#xff0c;将Multi后面的命令先进先出的顺序加入队列&#xff0c;在执行exce命令&#xff0c;将队列中的命令取出执行。配合redis完成事务的命令还有watch&#xff08;会…