图像分割方法与问题思考

前言

图像分割就是预测图像中每一个像素所属的类别或者物体。图像分割有两个子问题,一个是只预测类别层面的分割,对每个像素标出一个位置。第二个是区分不同物体的个体。应用场景,比如自动驾驶,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的输入只能是二值影像,这样并不能进行边缘的提取。请问有没有小伙伴有比较好的方法呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倾城一少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值