2019-07-02 22:08:48 qq_37486501 阅读数 184

数字图像处理中的图像分割

  1. 图像分割: 将图像分割成若干个互不相交的区域
  2. 基于灰度的不连续性
    (1): 边缘检测
    [
    基于一阶微分的各种梯度算子:
    基于二阶微分的拉普拉斯算子
    高斯-拉普拉斯算子(LOG算子): 用高斯平滑去噪, 用拉普拉斯进行边缘检测
    ]
    (2):轮廓提取与跟踪
    轮廓提取: 掏空内部点, 背景白前景黑, 从左上角扫描为“黑”=0, 且8邻域也都为黑, 则说明该像素点是目标物体内部点, 置”白“=1
    轮廓跟踪: 顺序地找出目标区域边界上的像素点, 以跟踪目标边界, 并且同时记录边界信息(边界链码)
    (3):Hough变换
  3. 基于灰度的相似性
    (1):灰度阈值分割:
    用一个或者几个灰度阈值T 将图像的灰度级范围分成几个部分, 将每个像素的灰度值和阈值相比较, 根据比较结果将像素归类——前景目标与背景区分开
    (2): 基于区域的分割
    [
    区域生长: 灰度相似则扩展
    区域的分裂与合并 : 按某种一致性准则, 不断分裂, 合并区域
    ]
2016-10-27 18:07:00 niaolianjiulin 阅读数 9861

从10月中旬开始,科研转为“Object Segment”,即物体分割。这属于图像理解范畴。图像理解包含众多,如图像分类、物体检测、物体分割、实例分割等若干具体问题。每个问题研究的范畴是什么?或者说每个问题中,对于某幅图像的处理结果是什么?整理如下。

Image Classification 

The task of object classification requires binary labels indicating whether objects are present in an image.[1]   图像分类,该任务需要我们对出现在某幅图像中的物体做标注。比如一共有1000个物体类,对一幅图中所有物体来说,某个物体要么有,要么没有。可实现:输入一幅测试图片,输出该图片中物体类别的候选集。

Object detection 

Detecting an object entails both stating that an object belonging to a specified class is present, and localizing it in the image. The location of an object is typically represented by a bounding box.  物体检测,包含两个问题,一是判断属于某个特定类的物体是否出现在图中;二是对该物体定位,定位常用表征就是物体的边界框。可实现:输入测试图片,输出检测到的物体类别和位置。

Semantic scene labeling 

The task of labeling semantic objects in a scene requires that each pixel of an image be labeled as belonging to a category, such as sky, chair, floor, street, etc. In contrast to the detection task, individual instances of objects do not need to be segmented. 语义标注/分割:该任务需要将图中每一点像素标注为某个物体类别。同一物体的不同实例不需要单独分割出来。对下图,标注为人,羊,狗,草地。而不需要羊1,羊2,羊3,羊4,羊5.

Instance segment  

实例分割是物体检测+语义分割的综合体。相对物体检测的边界框,实例分割可精确到物体的边缘;相对语义分割,实例分割可以标注出图上同一物体的不同个体(羊1,羊2,羊3...)


4种任务的数据集标注示例如图示。可以看到,标注越来越复杂,但是处理效果越来越有用。

参考文献

[1]  Microsoft COCO: Common Objects in Context. 主题:Dataset which Objects are labeled using per-instance segmentations.


2018-11-26 17:01:05 qq_40980917 阅读数 1971

电子科技大学 格拉斯哥学院 2017级谭茗珊
1.背景:
医学图像分割技术的发展是一个从人工分割到半自动分割和自动分割的逐步发展过程。早期的图像分割完全是靠人工完成的。完全的人工分割方法是在原始图像上直接画出期望的边界。这种方法费时费力,分割结果完全依赖于分割者的解剖知识和经验,而且分割结果难以再现;半自动的分割方法大大减少了人为因素的影响,而且分割速度快,分割精度高,但操作者的知识和经验仍然是图像分割过程的一个重要组成部分。近年来,由于大量的新兴技术如模糊技术和人工智能技术在图像分割中的应用,图像分割领域中也涌现出一些自动的分割技术。自动分割方法能完全脱离人为干预,由计算机实现医学图像分割的全过程。由于自动分割方法的运算量较大,目前大部分的自动分割方法都是在工作站上实现的。
2.摘要:
医学图像处理中图像分割是最具挑战性和最富有挑战性的课题,结构分析,运动分析,三维可视化等一系列操作均是以准确的图像分割为基础。由于医学影像设备成像技术的特点,使得图像存在噪声,导致图像中目标物体部分边缘不清晰,给图像分割造成一定难度。通过运用ITK-SNAP软件对图像进行预处理,使用python并搭建tensorflow环境,对图像加以训练和测试,不断改进算法改进现有MRI脑肿瘤图像分割算法,利用模糊C均值算法、区域增长算法、以及结合模糊相似度理论和区域结构识别技术的分割算法实现脑肿瘤MRI图像的分割,使其能够对图像进行准确识别,定性,定量分析,结果的准确性依据分割评价体系得以判断。

3.图像分割处理
3.1非线性平滑处理
由于磁共振图像在采集过程中,有脉冲干扰,因此图像具有较强的噪声,为了消除噪声,选用非线性平滑中值滤波预处理图片;
中值滤波是一种去除噪声的非线性处理方法。其基本思想是把数字图像中一点的值在该点的一个领域中各值的中值替代。
3.2全局阈值分割
一般图像分割是基于图像二值化的基础上进行的,其目的是可减少图像的灰度分布范围,简化运算,从而大大提高分割速度。
但如遇到特殊情况,例如脑部的头骨,高密度,灰度值高,处于亮区域,而我们感兴趣的区域(肿瘤)的灰度是软组织,灰度值低,处于暗区域。而肿瘤周围的软组织也是灰度值低的暗区域,与肿瘤的区别很小。此时,原始方法已不再能分辨。所以在程序中,必须舍弃。现有的二值化自动分割函数,改为手动的全局阈值分割。通过观察,设置特定的阈值点,从而进行有效手动分割,将处于亮区域的头骨和其他组织分割开,又保留了其他组织的原有特性。将其作为预处理图像

3.3肿瘤分割
经过手动的全局阈值分割后的图片,虽然消除了头骨的部分,但由于我们感兴趣的部分(肿瘤)并没有从周围组织里面分割出来,因此还需要进一步的处理。由于肿瘤和周围的组织灰度值比较接近,我们分别选用最大方差阈值法和形态学两种方法来处理。
3.3.1最大方差阈值法分割
最大方差阈值也叫大津阈值,他是在差别域最小二乘法原理的基础上推导出来的,不管是图像的直方图有无明显的双峰,此方法都能取得很好的效果。其原理是把直方图在某一阈值处分割成为两组,当被分成的两组间的方差为最大时,决定阈值。
3.3.2形态学分割
区域生长的基本思想是将具有相似性质的像素结合起来构成区域,具体是先对每个需要分割的区域找一个种子像素作为生长起点,然后将种子像素周围区域中与种子像素有相同或相似性质的像素种子合并到种子像素所在区域中,将这些新像素当作种子像素继续进行上面的过程,直到再也没有满足条件的像素可以被包括进来,这样,一个区域就生成了。经实验显示,采用形态学进行分割之后,脑部的肿瘤可以清晰地显示出来,但与此同时一些血管同时也显示出来了。
具体的算法步骤为:
求出图像的梯度;
采用圆形结构元素执行形态学开操作运算;
进行腐蚀运算;
采用圆形结构元素执行形态学闭运算操作;
进行膨胀运算;
经过开闭运算后,图像进行重建;
将重建的图像叠加在原有图像上。

4.结论:
由于医学图像的复杂多样性和分割问题的困难性,通常针对某项任务选用合适的算法,目前没有一个分割方法能适用于不同的任务,医学图像的分割方法有很多,最常用的方法是阈值分割法和形态学分割法。但通常,直接采用普通的阈值分割和形态学分割法,很难提取到满意的目标图像。本文分别对这两种方法稍作改进,采用图像阈值法时,先进行手动的阈值分割,然后再使用最大方差阈值法,效果更好;采用形态学分割时,圆形结构元素作为种子,也得到了目标图像。因此尽管医学图像分割比较复杂,只要灵活采用图像分割方法,可以得到比较满意的分割图像。

5.参考文献
[1]李彦东.卷积神经网络研究综述
[2]田捷.医学图像与医学分析[M].
[3]陈灵娜.一种新的肝肿瘤CT图像分割方法[J]
[4]马子睿.基于数字形态学的医学图像分割研究方法[J]
[5]俞海平.MRI脑肿瘤图像分割与矩特征研究[J]

2017-06-16 11:39:29 llh_1178 阅读数 20542

我们在处理图像的时候,常常需要将图像的前景和背景做不同的处理,这时需要将前景和背景分割开。关于图像分割的方法我知道的有三种方法:K-means、分水岭和GrabCut算法进行物体分割。不能够肯定的比较出谁优谁劣,各种算法是分各种场合以及设定参数的优化。在此,只是简单介绍,学习之路任重而道远!

K-means方法进行分割:

它是一种最常用的聚类算法。因为,人们不需要手动的为数据集里的每个个体添加标签,能自动的发现集群结构,进行分类。是一种无监督的学习。那么是什么定义了集群的呢?答案是通过中心和形状定义的。然后,通过打分判断依据是:在这个集群中的分数高于在其他聚类中的分数和与本集群中心点比其他集群中心点更相似。具体的步骤是:首先,把观测分配给最近的中心点。然后,把集群中心点修改为被分配给原中心点观测的均值,反复这两步操作,直到全部收敛。

关于OpenCV下的kmean算法,函数为cv2.kmeans()
函数的格式为:kmeans(data, K, bestLabels, criteria, attempts, flags)

其中,K(分类数)和 attempts(Kmeans算法重复次数)是需要根据具体的图像进行优化的参数。像bestLabels预设分类标签可以不需要用None表示,criteria为迭代停止的模式选择,格式为(type,max_iter,epsilon),其中type又有两种选择:cv2.TERM_CRITERIA_EPS :精确度(误差)满足epsilon停止和cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过max_iter停止,也可以两者结合,满意任意一个就结束。而flags(初始类中心选择),有两种方法:cv2.KMEANS_PP_CENTERS ; cv2.KMEANS_RANDOM_CENTERS

下面,就尝试一下修改K(分类数)和 attempts(Kmeans算法重复次数)参数进行测试。

先将K设为默认值,调attempts次数。

# 以灰色导入图像
img = cv2.imread('messi5.jpg',0)#image read be 'gray'
plt.subplot(221),plt.imshow(img,'gray'),plt.title('original')
plt.xticks([]),plt.yticks([])

# 改变图像的维度
img1 = img.reshape((img.shape[0]*img.shape[1],1))
img1 = np.float32(img1)

# 设定一个criteria,
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,10,1.0)

# 设定一个初始类中心flags
flags = cv2.KMEANS_RANDOM_CENTERS
# 应用K-means
compactness,labels,centers = cv2.kmeans(img1,2,None,criteria,5,flags)
compactness_1,labels_1,centers_1 = cv2.kmeans(img1,2,None,criteria,10,flags)
compactness_2,labels_2,centers_2 = cv2.kmeans(img1,2,None,criteria,15,flags)
img2 = labels.reshape((img.shape[0],img.shape[1]))
img3 = labels_1.reshape((img.shape[0],img.shape[1]))
img4 = labels_2.reshape((img.shape[0],img.shape[1]))
plt.subplot(222),plt.imshow(img2,'gray'),plt.title('kmeans_attempts_5')
plt.xticks([]),plt.yticks([])
plt.subplot(223),plt.imshow(img3,'gray'),plt.title('kmeans_attempts_10')
plt.xticks([]),plt.yticks([])
plt.subplot(224),plt.imshow(img4,'gray'),plt.title('kmeans_attempts_15')
plt.xticks([]),plt.yticks([])
plt.savefig("kmeans_attempts.png")
plt.show()



可以看出attempts次数不同,是会造成图像分割差异的。

再来调K值,这里将attempts次数设为10.得到的图像为:


也可以看出K初始值不同,同样造成图像分割差异。所以,可以说这两个参数的优化是很重要的,但是,也不容易优化。看下一种方法:

分水岭算法

之所以叫分水岭算法,是因为它里面有“水”的概念。把图像中低密度的区域(变化很少)想象成山谷,图像中高密度的区域(变化很多)想象成山峰。开始向山谷中注入水直到不同的山谷中的水开始汇集。为了阻止不同山谷的水汇聚,可以设置一些栅栏,最后得到的栅栏就是图像分割。

img = cv2.imread("water_coins.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 将颜色转变为灰色之后,可为图像设一个阈值,将图像二值化。
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 下面用morphologyEx变换来除去噪声数据,这是一种对图像进行膨胀之后再进行腐蚀的操作,它可以提取图像特征:
kernel = np.ones((3,3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations= 2)
# 通过对morphologyEx变换之后的图像进行膨胀操作,可以得到大部分都是背景的区域:
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# 接着通过distanceTransform来获取确定前景区域,原理是应用一个阈值来决定哪些区域是前景,越是远离背景区域的边界的点越可能属于前景。
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# 考虑前景和背景中有重合的部分,通过sure_fg和sure_bg的集合相减得到。
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
# 现在有了这些区域,就可以设定“栅栏”来阻止水汇聚了,这通过connectedComponents函数来完成
ret, markers = cv2.connectedComponents(sure_fg)
# 在背景区域上加1, 这会将unknown区域设置为0:
markers = markers + 1
markers[unknown==255] = 0
# 最后打开门,让水漫起来并把栅栏绘成红色
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]
plt.imshow(img), plt.xticks([]),plt.yticks([])
plt.show()



能够看出还是能大多数完整分割。

接下来介绍GrabCut算法进行对图像的分割处理。

使用GrabCut算法的实现步骤为:
1)在图片中定义含有(一个或多个)物体的矩形
2)矩形外的区域被自动认为是背景
3)对于用户定义的矩形区域,可用背景中的数据来区别它里面的前景和背景区域
4)用高斯混合模型(GMM)来对背景和前景建模,并将末定义的像素标记为可能的前景或背景
5)图像中的每一个像素都被看作通过虚拟边与周围像素相连接,而每一条边都有一个属于前景或背景的概率,这基于它与周围像素颜色上的相似性
6)每一个像素会与一个前景或背景节点连接。若节点之间不属于同一个终端(就是两个相邻的节点,一个节点属于前景,一个节点属于背景),则会切断它们之间的边,这就将图像各个部分分割出来了。

import numpy as np
import cv2
from matplotlib import pyplot as plt

# 首先加载图片,然后创建一个与所加载图片同形状的掩模,并用0填充。
img = cv2.imread("messi5.jpg")
mask = np.zeros(img.shape[:2], np.uint8)

# 然后创建以0填充的前景和背景模型:
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
# 在实现GrabCut算法前,先用一个标识出想要隔离的对象的矩形来初始化它,这个矩形我们用下面的一行代码定义(x,y,w,h):
rect = (100, 50, 421, 378)
# 接下来用指定的空模型和掩摸来运行GrabCut算法
#mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT) # 5是指算法的迭代次数。
# 然后,我们再设定一个掩模,用来过滤之前掩模中的值(0-3)。值为0和2的将转为0,值为1和3的将转化为1,这样就可以过滤出所有的0值像素(背景)。
mask2 = np.where((mask==2)|(mask==0), 0, 1).astype("uint8")
img = img * mask2[:, :, np.newaxis]
# 最后可视化展现分割前后的图像
plt.subplot(1, 2, 1)
plt.imshow(img)
plt.title("grabcut"), plt.xticks([]), plt.yticks([])

plt.subplot(1, 2, 2)
plt.imshow(cv2.imread("messi5.jpg"))
plt.title("original"), plt.xticks([]), plt.yticks([])
plt.savefig("grabcut.png")



可以看出来分割的并不完整,而且头发和手都没有被区分到前景中来,这是因为,在设定矩形的时候需要不断优化的,且因每一张图像都有差异,所以矩形的范围也是有差异的。还好在github上找到了一个grabcut算法脚本,能完美的解决这个问题。并用他的代码进行测试。如下图:





参考:

《OpenCV3计算机视觉Python语言实现》

OpenCV帮助文档:

http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_grabcut/py_grabcut.html

https://github.com/opencv/opencv/blob/master/samples/python/grabcut.py


2019-05-22 17:39:49 weixin_44403952 阅读数 318

全局阈值

全局阈值就是在整个图像中将灰度阈值设置成一个常数,全局阈值适合如下场景:图像背景的灰度值在整个图像中可合理的看作恒定,而且所有物体和背景都具有几乎相同的对比度,反应在直方图上就是 具有明显的双峰。在此种情况下,只要选择合适的阈值,使用固定的全局阈值往往会有比较好的效果。全局阈值选择的主要方法有:人工选择法、直方图选择法、迭代式阈值选择法、最大类间方差阈值(Otsu)。
在OpenCV中图像的二值化分割采用的是 cv2.threshold(src, thresh, maxval, type, dst=None)

  • 第一个参数src: 原图像
  • 第二个参数thresh: 分类的阈值
  • 第三个参数 maxval:高于阈值时选取的新的值
  • 第四个参数maxval: 就是 上述介绍的几个方法选择参数
    常用的有:• cv2.THRESH_BINARY(黑白二值)
    • cv2.THRESH_BINARY_INV(黑白二值反转)
    • cv2.THRESH_TRUNC (得到的图像为多像素值)
    • cv2.THRESH_TOZERO
    • cv2.THRESH_TOZERO_INV
  • 返回值(2个):第一个 retVal: 得到的阈值,第二个 就是阈值化后的图像
import cv2
import numpy as np
img = cv2.imread("sources/lena_1.tiff",0)
from matplotlib import pyplot as plt

ret , thresh = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV )
#ret , thresh = cv2.threshold(img,127,255,cv2.THRESH_OTSU )
cv2.imshow("1",thresh)
cv2.waitKey(0)

自适应阈值

在很多情况下,背景的灰度值并不是常数,物体和背景的对比度在图像中是变化的,此时一个图像中某个区域效果良好的阈值在其他区域可能会效果很差。在这种情况下,需要把灰度阈值取为一个随图像中位置缓慢变化的函数值,也就是自适应阈值。
自适应阈值主要的方法就是将图像进一步划分为子图像,并对不同的子图像使用不同的阈值进行分割。此方法的关键问题就是如何将图像进行细分和如何为得到的子图像估计阈值。
自适应阈值的经典算法是: 分水岭算法,详情参考博文:https://blog.csdn.net/dcrmg/article/details/52498440
OpenCV的自适应阈值函数为:
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C, dst=None)

  • 第一个参数src: 原图像
  • 第二个参数maxVal: 像素的最大值
  • 第三个参数 adaptiveMethod(有两种方法):
    cv2.ADAPTIVE_THRESH_MEAN_C:邻域内均值
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C:邻域内像素点加权和,权重为一个高斯窗口
    第四个参数thresholdType:有 cv2.THRESH_BINARY、cv2.THRESH_BINARY_INV两个
    第五个参数Block Size:规定的邻域大小
    第六个参数 C:设置阈值为 (均值 - C) 或者是 (加权值 - C)

返回值: 只有一个,就是二值化后的图像

import cv2
import numpy as np
img = cv2.imread("sources/lena_1.tiff",0)
from matplotlib import pyplot as plt

thresh = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,10)

cv2.imshow("1",thresh)
cv2.waitKey(0)

- 显示效果
------ 全局阈值
图1
-----局部阈值自适应调整
图2

  • 分析
    最后两个参数,是用来调整子图像大小(子图像边长只能为奇数) 以及 局部子图像阈值自适应调整。这两个参数用来改善二值化的图像的质量。当子图像的大小调整到原图像大小时,该方法退化为 全局阈值调整。

图像分割

阅读数 1105

没有更多推荐了,返回首页