精华内容
下载资源
问答
  • 简单的来讲就是给一张图像,检测是用框出框出物体,而图像分割分出一个物体的准确轮廓。也这样考虑,给出一张图像 I,这个问题就是求一个函数,从I映射到Mask。至于怎么求这个函数有多种方法。我们可以看到这个图...

    ##背景
    分割

    	Mask = Function(I)
    
    1. 什么是图像分割问题呢? 简单的来讲就是给一张图像,检测是用框出框出物体,而图像分割分出一个物体的准确轮廓。也这样考虑,给出一张图像 I,这个问题就是求一个函数,从I映射到Mask。至于怎么求这个函数有多种方法。我们可以看到这个图,左边是给出图像,可以看到人和摩托车,右边是分割结果。
      图二
    2. 求这个函数有很多方法,但是第一次将深度学习结合起来的是这篇文章全卷积网络(FCN),利用深度学习求这个函数。在此之前深度学习一般用在分类和检测问题上。由于用到CNN,所以最后提取的特征的尺度是变小的。和我们要求的函数不一样,我们要求的函数是输入多大,输出有多大。为了让CNN提取出来的尺度能到原图大小,FCN网络利用上采样和反卷积到原图像大小。然后做像素级的分类。可以看图二,输入原图,经过VGG16网络,得到特征map,然后将特征map上采样回去。再将预测结果和ground truth每个像素一一对应分类,做像素级别分类。也就是说将分割问题变成分类问题,而分类问题正好是深度学习的强项。如果只将特征map直接上采样或者反卷积,明显会丢失很多信息。

    图三
    3. FCN采取解决方法是将pool4、pool3、和特征map融合起来,由于pool3、pool4、特征map大小尺寸是不一样的,所以融合应该前上采样到同一尺寸。这里的融合是拼接在一起,不是对应元素相加。

    图四
    4. FCN是深度学习在图像分割的开山之作,FCN优点是实现端到端分割等,缺点是分割结果细节不够好,可以看到图四,FCN8s是上面讲的pool4、pool3和特征map融合,FCN16s是pool4和特征map融合,FCN32s是只有特征map,得出结果都是细节不够好,具体可以看自行车。由于网络中只有卷积没有全连接,所以这个网络又叫全卷积网络。

    ##Unet网络结构图五

    1. 很多分割网络都是基于FCNs做改进,包括Unet。Unet包括两部分,可以看右图,第一部分,特征提取,VGG类似。第二部分上采样部分。由于网络结构像U型,所以叫Unet网络。

      1. 特征提取部分,每经过一个池化层就一个尺度,包括原图尺度一共有5个尺度。
      2. 上采样部分,每上采样一次,就和特征提取部分对应的通道数相同尺度融合,但是融合之前要将其crop。这里的融合也是拼接。
        个人认为改进FCN之处有:
        1. 多尺度
        2. 适合超大图像分割,适合医学图像分割
    2. Unet——输入输出
      图六
      医学图像是一般相当大,但是分割时候不可能将原图太小输入网络,所以必须切成一张一张的小patch,在切成小patch的时候,Unet由于网络结构原因适合有overlap的切图,可以看图,红框是要分割区域,但是在切图时要包含周围区域,overlap另一个重要原因是周围overlap部分可以为分割区域边缘部分提供文理等信息。可以看黄框的边缘,分割结果并没有受到切成小patch而造成分割情况不好。
      3.Unet——反向传播
      Unet反向传播过程,大家都知道卷积层和池化层都能反向传播,Unet上采样部分可以用上采样或反卷积,那反卷积和上采样可以怎么反向传播的呢?那什么是反卷积呢?先来讲下卷积的过程

       				Y = Matrix_1(Filter)* Matrix_2(Image)
      

    Matrix_1和Matrix_2分别是将卷积核和图像转成矩阵函数。也就说给一个输入X,利用矩阵乘法能得到卷积后输出Y。

    								Y=C*X
    

    所以卷积可以分解成两个矩阵相乘。很显然,卷积反向传播就是C的转置相乘。举个例子:

    							Y=[1,2]*[X,x_1]T
    

    Y对x求导,dy/dx=[1,2]^T。
    图7
    反卷积就是转置卷积,也是一种卷积,可以看到图7,这个就是转置卷积,由小尺寸到大尺寸的过程。也就是说反卷积也可以表示为两个矩阵乘积,很显然转置卷积的反向传播就是也是可进行的。所以说整体是Unet是可以反向传播的。
    3.Unet——与其他结构比较之FPN
    这里写图片描述
    这是FPN检测网络,可以看到红框,如果将红框到过来可以发现,FPN部分结构和Unet相似之处。从而说明Unet网络结构是基于多尺度的。

    如果大家觉的文章有帮助或者有用,麻烦关注下我的个人公众号
    在这里插入图片描述

    展开全文
  • 语义分割、实例分割和全景分割的区别

    千次阅读 多人点赞 2019-05-14 19:59:27
    之前看过一篇使用分割思想进行目标检测,所以这里补习下一些分割相关的基础知识。这里重点说下语义分割、实力分割和全景分割的区别。 1 、semantic segmentation(语义分割) 通常意义上的目标分割指的就是语义...

    之前看过一篇使用分割思想进行目标检测,所以这里补习下一些分割相关的基础知识。这里重点说下语义分割、实力分割和全景分割的区别。

    1 、semantic segmentation(语义分割)

    通常意义上的目标分割指的就是语义分割,图像语义分割,简而言之就是对一张图片上的所有像素点进行分类

    语义分割(下图左)就是需要区分到图中每一点像素点,而不仅仅是矩形框框住了。但是同一物体的不同实例不需要单独分割出来。对下图左,标注为人,羊,狗,草地。而不需要羊1,羊2,羊3,羊4,羊5等。

    2、Instance segmentation(实例分割)

    实例分割(上图右)其实就是目标检测语义分割的结合。相对目标检测的边界框,实例分割可精确到物体的边缘相对语义分割,实例分割需要标注出图上同一物体的不同个体(羊1,羊2,羊3...)

    3、Panoramic segmentation(全景分割)

    全景分割语义分割实例分割的结合。

    跟实例分割不同的是:实例分割只对图像中的object进行检测,并对检测到的object进行分割,而全景分割是对图中的所有物体包括背景都要进行检测和分割。

    最后放上一张总结的图片

    å¨è¿éæå¥å¾çæè¿°

     

    参考文章:

    图像分类、目标检测、语义分割、实例分割和全景分割的区别

    (科普)——实例分割、语义分割、全景分割的区别

    展开全文
  • 在之前的一篇博客里:医学图像分割 unet实现(一),是学习并复现别人的实验。这篇将记录下自己毕设第一阶段的实验。毕设题目为:基于深度学习的肝脏肿瘤分割。 经过几番调整,最终确定:第一阶段分割出腹部图像中的...

    在之前的一篇博客里:医学图像分割 unet实现(一),是学习并复现别人的实验。这篇将记录下自己毕设第一阶段的实验。毕设题目为:基于深度学习的肝脏肿瘤分割。
    经过几番调整,最终确定:第一阶段分割出腹部图像中的肝脏,作为第二阶段的ROI(region of interest),第二阶段利用ROI对腹部图像进行裁剪,裁剪后的非ROI区域变成黑色,作为该阶段输入,分割出肝脏中的肿瘤(更新2019-4-2,已做完实验,医学图像分割 基于深度学习的肝脏肿瘤分割 实战(二)。第三阶段用随机场的后处理方法进行优化。
    此外,觉得当时的那篇文章写得很不用心,没费多大功夫,复制粘贴为主。我记录的主要原因之一就是觉得这方面入门实战的文章很少,希望让情况类似的同学少走一点弯路。可现在自己写的东西过几天再去看,都会一头雾水。没有从主干思路到细节的分层讲解,没有关键点的介绍。这篇文章开始,将尽我所能,写得利于接受一点。
    (不过,自己才开始学习一个多月,python和框架都是临时学的,并不能保证博客里的东西是对的,有错误的话,望指出)

    正文:

    目标

    分割出CT腹部图像的肝脏区域。

    原始数据介绍

    实验用到的数据为3Dircadb,即腹部的CT图。一个病人为一个文件夹。
    例如3Dircadb1.1(一共20位),该文件夹下会使用到的子文件夹为PATIENT_DICOM(病人原始腹部3D CT图),MASKS_DICOM(该文件夹下具有不同部位的分割结果,比如liver和liver tumor等等)。如下图所示:
    在这里插入图片描述
    PATIENT_DICOM利用软件展示效果如下:一个dcm文件包含129张切片。
    在这里插入图片描述
    MASKS_DICOM下的liver分割图效果如下:
    在这里插入图片描述

    整体思路

    1、数据提取

    数据读取:
    从原始dcm格式读入成我们需要的数组格式

    #part1
    import numpy as np
    import pydicom
    import os
    import matplotlib.pyplot as plt
    import cv2
    from keras.preprocessing.image import ImageDataGenerator
    from HDF5DatasetWriter import HDF5DatasetWriter
    from HDF5DatasetGenerator import HDF5DatasetGenerator
    
    for i in range(1,18): # 前17个人作为测试集
       full_images = [] # 后面用来存储目标切片的列表
       full_livers = [] #功能同上
       # 注意不同的系统,文件分割符的区别
       label_path = '~/3Dircadb/3Dircadb1.%d/MASKS_DICOM/liver'%i
       data_path = '~/3Dircadb/3Dircadb1.%d/PATIENT_DICOM'%i
       liver_slices = [pydicom.dcmread(label_path + '/' + s) for s in os.listdir(label_path)]
       # 注意需要排序,即使文件夹中显示的是有序的,读进来后就是随机的了
       liver_slices.sort(key = lambda x: int(x.InstanceNumber))
       # s.pixel_array 获取dicom格式中的像素值
       livers = np.stack([s.pixel_array for s in liver_slices])
       image_slices = [pydicom.dcmread(data_path + '/' + s) for s in os.listdir(data_path)]
       image_slices.sort(key = lambda x: int(x.InstanceNumber))
       
       """ 省略进行的预处理操作,具体见part2"""
       
       full_images.append(images)
       full_livers.append(livers)
       
       full_images = np.vstack(full_images)
       full_images = np.expand_dims(full_images,axis=-1)
       full_livers = np.vstack(full_livers)
       full_livers = np.expand_dims(full_livers,axis=-1)
    

    2、数据的预处理

    1、将ct值转化为标准的hu值
    至于为什么要将值进行转化,这儿就不详细说明,具体可以参考医学图像预处理(三)——windowing(ct对比增强),这篇博文中有一样的get_pixels_hu函数
    2、窗口化操作
    医学图像预处理(三)——windowing(ct对比增强)
    3、直方图均衡化

    def clahe_equalized(imgs,start,end):
       assert (len(imgs.shape)==3)  #3D arrays
       #create a CLAHE object (Arguments are optional).
       clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
       imgs_equalized = np.empty(imgs.shape)
       for i in range(start, end+1):
           imgs_equalized[i,:,:] = clahe.apply(np.array(imgs[i,:,:], dtype = np.uint8))
       return imgs_equalized
    

    4、归一化
    5、仅提取腹部所有切片中包含了肝脏的那些切片,其余的不要
    医学图像预处理(四)—— 提取包含目标的切片

    #part2
        # 接part1
       images = get_pixels_hu(image_slices)
       
       images = transform_ctdata(images,500,150)
       
       start,end = getRangImageDepth(livers)
       images = clahe_equalized(images,start,end)
       
       images /= 255.
       # 仅提取腹部所有切片中包含了肝脏的那些切片,其余的不要
      
       total = (end - 4) - (start+4) +1
       print("%d person, total slices %d"%(i,total))
       # 首和尾目标区域都太小,舍弃
       images = images[start+5:end-5]
       print("%d person, images.shape:(%d,)"%(i,images.shape[0]))
       
       livers[livers>0] = 1
       
       livers = livers[start+5:end-5]
    

    3、数据增强

    利用keras的数据增强接口,可以实现分割问题的数据增强。一般的增强是分类问题,这种情况,只需要对image变形,label保持不变。但分割问题,就需要image和mask进行同样的变形处理。具体怎么实现,参考下面代码,注意种子设定成一样的。

    # 可以在part1之前设定好(即循环外)
    seed=1
    data_gen_args = dict(rotation_range=3,
                        width_shift_range=0.01,
                        height_shift_range=0.01,
                        shear_range=0.01,
                        zoom_range=0.01,
                        fill_mode='nearest')
    
    image_datagen = ImageDataGenerator(**data_gen_args)
    mask_datagen = ImageDataGenerator(**data_gen_args)
    
    #part3 接part2
        image_datagen.fit(full_images, augment=True, seed=seed)
        mask_datagen.fit(full_livers, augment=True, seed=seed)
        image_generator = image_datagen.flow(full_images,seed=seed)
        mask_generator = mask_datagen.flow(full_livers,seed=seed)
    
        train_generator = zip(image_generator, mask_generator)
        x=[]
        y=[]
        i = 0
        for x_batch, y_batch in train_generator:
            i += 1
            x.append(x_batch)
            y.append(y_batch)
            if i>=2: # 因为我不需要太多的数据
                break
        x = np.vstack(x)
        y = np.vstack(y)
    

    4、数据存储

    一般而言,数据量较大的话,都会先将原始数据库的东西转化为np或者h5格式的文件,我感觉这样有两个好处,一是真正输入网络训练的时候io量会大大减少(特别是h5很适用于大的数据库),二是数据分享或者上传至服务器时也方便一点。

    实验中会出现两个类,分别是写h5和读h5文件的辅助类
    这读文件的类写成了generator,这样可以结合训练网络时,keras的fit_generator来使用,降低内存开销。

    class HDF5DatasetWriter:
    	"""用来写数据到h5文件"""
    class HDF5DatasetGenerator:
        """用来读h5文件的数据"""
    

    它们具体的实现在python h5文件的读写,因为篇幅问题,所以这儿不详述

    h5文件操作需要的包import h5py

    # 可以在part1之前设定好(即循环外)
    # 这儿的数量需要提前写好,感觉很不方便,但不知道怎么改,我是先跑了之前的程序,计算了一共有多少
    # 张图片后再写的,但这样明显不是好的解决方案
    dataset = HDF5DatasetWriter(image_dims=(2782, 512, 512, 1),
                                mask_dims=(2782, 512, 512, 1),
                                outputPath="data_train/train_liver.h5")
    
    #part4 接part3
        dataset.add(full_images, full_livers)
        dataset.add(x, y)
        # end of lop
    dataset.close()
    

    测试数据存储的全部过程

    测试数据与上面训练数据的处理过程几乎一样,但测试数据不要进行数据增强

    full_images2 = []
    full_livers2 = []
    for i in range(18,21):#后3个人作为测试样本
        label_path = '~/3Dircadb/3Dircadb1.%d/MASKS_DICOM/liver'%i
        data_path = '~/3Dircadb/3Dircadb1.%d/PATIENT_DICOM'%i
        liver_slices = [pydicom.dcmread(label_path + '/' + s) for s in os.listdir(label_path)]
        liver_slices.sort(key = lambda x: int(x.InstanceNumber))
        livers = np.stack([s.pixel_array for s in liver_slices])
        start,end = getRangImageDepth(livers)
        total = (end - 4) - (start+4) +1
        print("%d person, total slices %d"%(i,total))
        
        image_slices = [pydicom.dcmread(data_path + '/' + s) for s in os.listdir(data_path)]
        image_slices.sort(key = lambda x: int(x.InstanceNumber))
        
        images = get_pixels_hu(image_slices)
        images = transform_ctdata(images,500,150)
        images = clahe_equalized(images,start,end)
        images /= 255.
        images = images[start+5:end-5]
        print("%d person, images.shape:(%d,)"%(i,images.shape[0]))
        livers[livers>0] = 1
        livers = livers[start+5:end-5]
    
        full_images2.append(images)
        full_livers2.append(livers)
        
    full_images2 = np.vstack(full_images2)
    full_images2 = np.expand_dims(full_images2,axis=-1)
    full_livers2 = np.vstack(full_livers2)
    full_livers2 = np.expand_dims(full_livers2,axis=-1)
    
    dataset = HDF5DatasetWriter(image_dims=(full_images2.shape[0], full_images2.shape[1], full_images2.shape[2], 1),
                                mask_dims=(full_images2.shape[0], full_images2.shape[1], full_images2.shape[2], 1),
                                outputPath="data_train/val_liver.h5")
    
    
    dataset.add(full_images2, full_livers2)
    
    print("total images in val ",dataset.close())
    

    5、构建网络

    这一部分不多说,是直接用的别人写好的Unet。
    唯一进行的更改,就是Crop的那部分。因为,如果输入图片的高或者宽不能等于2^n(n>=m),m为网络收缩路径的层数。那么出现的问题就是,下采样的时候进行了取整操作,但是,后续在扩张路径又会有上采样,且上采样的结果会和收缩路径的特征图进行拼接,即long skip connection。若没有达到上面提到的要求,会导致拼接的两个特征图size不同,报错。

    # partA
    import os
    import sys
    import numpy as np
    import random
    import math
    import tensorflow as tf
    from HDF5DatasetGenerator import HDF5DatasetGenerator
    from keras.models import Model
    from keras.layers import Input, concatenate, Conv2D, MaxPooling2D, Conv2DTranspose,Cropping2D
    from keras.optimizers import Adam
    from keras.callbacks import ModelCheckpoint
    from keras import backend as K
    from skimage import io
    
    
    K.set_image_data_format('channels_last')
        
    def dice_coef(y_true, y_pred):
        smooth = 1.
        y_true_f = K.flatten(y_true)
        y_pred_f = K.flatten(y_pred)
        intersection = K.sum(y_true_f * y_pred_f)
        return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)
    
    
    def dice_coef_loss(y_true, y_pred):
        return -dice_coef(y_true, y_pred)
    
    def get_crop_shape(target, refer):
            # width, the 3rd dimension
            print(target.shape)
            print(refer._keras_shape)
            cw = (target._keras_shape[2] - refer._keras_shape[2])
            assert (cw >= 0)
            if cw % 2 != 0:
                cw1, cw2 = int(cw/2), int(cw/2) + 1
            else:
                cw1, cw2 = int(cw/2), int(cw/2)
            # height, the 2nd dimension
            ch = (target._keras_shape[1] - refer._keras_shape[1])
            assert (ch >= 0)
            if ch % 2 != 0:
                ch1, ch2 = int(ch/2), int(ch/2) + 1
            else:
                ch1, ch2 = int(ch/2), int(ch/2)
    
            return (ch1, ch2), (cw1, cw2)
    
    def get_unet():
        inputs = Input((IMG_HEIGHT, IMG_WIDTH , 1))
        conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)
        conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
        pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
    
        conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1)
        conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
        pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
    
        conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2)
        conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
        pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
    
        conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3)
        conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)
        pool4 = MaxPooling2D(pool_size=(2, 2))(conv4)
    
        conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4)
        conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5)
    
        up_conv5 = Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(conv5)
        
        ch, cw = get_crop_shape(conv4, up_conv5)
        
        crop_conv4 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv4)
        up6 = concatenate([up_conv5, crop_conv4], axis=3)
        conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6)
        conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6)
        
        up_conv6 = Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(conv6)
    
        ch, cw = get_crop_shape(conv3, up_conv6)
        crop_conv3 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv3)
        
        up7 = concatenate([up_conv6, crop_conv3], axis=3)
        conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7)
        conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7)
        
        up_conv7 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv7)
        ch, cw = get_crop_shape(conv2, up_conv7)
        crop_conv2 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv2)
    
        up8 = concatenate([up_conv7, crop_conv2], axis=3)
        conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8)
        conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8)
        
        up_conv8 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv8)
        ch, cw = get_crop_shape(conv1, up_conv8)
        crop_conv1 = Cropping2D(cropping=(ch,cw), data_format="channels_last")(conv1)
    
    
        up9 = concatenate([up_conv8, crop_conv1], axis=3)
        conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9)
        conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9)
    
        conv10 = Conv2D(1, (1, 1), activation='sigmoid')(conv9)
    
        model = Model(inputs=[inputs], outputs=[conv10])
    
        model.compile(optimizer=Adam(lr=1e-5), loss=dice_coef_loss, metrics=[dice_coef])
    
        return model
    

    6、进行训练并测试

    这其中主要包括训练文件与测试文件的读取,Checkpoint回掉函数的设定,fit_generator的使用,模型预测,并对预测结果进行保存。

    # partB 接partA
    IMG_WIDTH = 512
    IMG_HEIGHT = 512
    IMG_CHANNELS = 1
    TOTAL = 2782 # 总共的训练数据
    TOTAL_VAL = 152 # 总共的validation数据
    # part1部分储存的数据文件
    outputPath = './data_train/train_liver.h5' # 训练文件
    val_outputPath = './data_train/val_liver.h5'
    #checkpoint_path = 'model.ckpt'
    BATCH_SIZE = 8 # 根据服务器的GPU显存进行调整
    
    class UnetModel:
        def train_and_predict(self):
            
            reader = HDF5DatasetGenerator(dbPath=outputPath,batchSize=BATCH_SIZE)
            train_iter = reader.generator()
            
            test_reader = HDF5DatasetGenerator(dbPath=val_outputPath,batchSize=BATCH_SIZE)
            test_iter = test_reader.generator()
            fixed_test_images, fixed_test_masks = test_iter.__next__()
    #   
            
            model = get_unet()
            model_checkpoint = ModelCheckpoint('weights.h5', monitor='val_loss', save_best_only=True)
            # 注:感觉validation的方式写的不对,应该不是这样弄的
            model.fit_generator(train_iter,steps_per_epoch=int(TOTAL/BATCH_SIZE),verbose=1,epochs=500,shuffle=True,
                                validation_data=(fixed_test_images, fixed_test_masks),callbacks=[model_checkpoint])
    #        
            reader.close()
            test_reader.close()
            
            
            print('-'*30)
            print('Loading and preprocessing test data...')
            print('-'*30)
            
            print('-'*30)
            print('Loading saved weights...')
            print('-'*30)
            model.load_weights('weights.h5')
        
            print('-'*30)
            print('Predicting masks on test data...')
            print('-'*30)
            
            
            imgs_mask_test = model.predict(fixed_test_images, verbose=1)
            np.save('imgs_mask_test.npy', imgs_mask_test)
        
            print('-' * 30)
            print('Saving predicted masks to files...')
            print('-' * 30)
            pred_dir = 'preds'
            if not os.path.exists(pred_dir):
                os.mkdir(pred_dir)
            i = 0
            
            
            for image in imgs_mask_test:
                image = (image[:, :, 0] * 255.).astype(np.uint8)
                gt = (fixed_test_masks[i,:,:,0] * 255.).astype(np.uint8)
                ini = (fixed_test_images[i,:,:,0] *255.).astype(np.uint8)
                io.imsave(os.path.join(pred_dir, str(i) + '_ini.png'), ini)
                io.imsave(os.path.join(pred_dir, str(i) + '_pred.png'), image)
                io.imsave(os.path.join(pred_dir, str(i) + '_gt.png'), gt)
                i += 1
    
    unet = UnetModel()
    unet.train_and_predict()
    

    模型跑的过程如图。
    在这里插入图片描述
    预测结果可视化展示
    在这里插入图片描述

    展开全文
  • Opencv 图像分割: 阈值化分割 区域分割 边缘分割 卷积 就是两个函数之间的相互关系,然后得出一个新的值,在连续空间做积分计算,然后在离散空间内求和的过程。 在计算机视觉里面,可以把卷积当做一个抽象的过程...

    Opencv 图像分割: 阈值化分割 区域分割 边缘分割

    卷积
    就是两个函数之间的相互关系,然后得出一个新的值,在连续空间做积分计算,然后在离散空间内求和的过程。
    在计算机视觉里面,可以把卷积当做一个抽象的过程,就是把小区域内的信息统计抽象出来

    图像阈值化分割
    按照灰度级,对像素集合进行一个划分,得到的每个子集形成一个与现实景物相对应的区域,
    各个区域内部具有一致的属性,而相邻区域不具有这种一致属性。
    它是一种传统的最常用的图像分割方法,因计算简单、运算效率较高、速度快、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。
    它特别适用于目标和背景占据不同灰度级范围的图像,在极大的压缩数据量的同时也大大简化了分析和处理步骤,是进行图像分析、特征提取与模式识别之前的必要的图像预处理过程。
    它有全局阈值、自适应阈值、最佳阈值等

    二值化cvThreshold

    /* Applies fixed-level threshold to grayscale image.
       This is a basic operation applied before retrieving contours */
    CVAPI(double)  cvThreshold( const CvArr*  src, CvArr*  dst,
                                double  threshold, double  max_value,
                                int threshold_type );

    src输入图像,须为单通道灰度图。
    dst输出的边缘图像,为单通道黑白图。
    threshold表示阈值
    max_value表示最大值。
    threshold_type表示二值化类型(即对图像取阈值的方法)

    /* Threshold types */
    enum
    {
        CV_THRESH_BINARY      =0,  /* value = value > threshold ? max_value : 0       */
        //if src(x,y)>threshold dst(x,y) = max_value, 
        //otherwise  dst(x,y) = 0,
    
        CV_THRESH_BINARY_INV  =1,  /* value = value > threshold ? 0 : max_value       */
        //if src(x,y)>threshold dst(x,y) = 0, 
        //otherwise  dst(x,y) = max_value,
    
        CV_THRESH_TRUNC       =2,  /* value = value > threshold ? threshold : value   */
        //if src(x,y)>threshold dst(x,y) = threshold, 
        //otherwise  dst(x,y) = src(x,y),
    
        CV_THRESH_TOZERO      =3,  /* value = value > threshold ? value : 0           */
         //if src(x,y)>threshold dst(x,y) = src(x,y), 
        //otherwise  dst(x,y) = 0,
    
        CV_THRESH_TOZERO_INV  =4,  /* value = value > threshold ? 0 : value           */
         //if src(x,y)>threshold dst(x,y) = 0, 
        //otherwise  dst(x,y) = src(x,y),
    
        CV_THRESH_MASK        =7,
        CV_THRESH_OTSU        =8  /* use Otsu algorithm to choose the optimal threshold value;
                                     combine the flag with one of the above CV_THRESH_* values */
        //threshold_type使用CV_THRESH_OTSU,则cvThreshold()将使用大律法OTSU得到的全局自适应阈值来进行二值化图像,而参数中的threshold不再起作用
    };
    如:cvThreshold(grayImg, binaryImg, 145, 255, CV_THRESH_BINARY); //二值图

    自适应二值化cvAdaptiveThreshold
    函数使用Otsu算法(大律法或最大类间方差法)来计算出一个全局阈值,然后根据这个阈值进行二值化
    Otsu实现思路
    1、计算0~255各灰阶对应的像素个数,保存至一个数组中,该数组下标是灰度值,保存内容是当前灰度值对应像素数
    2、计算背景图像的平均灰度、背景图像像素数所占比例
    3、计算前景图像的平均灰度、前景图像像素数所占比例
    4、遍历0~255各灰阶,计算并寻找类间方差极大值,此时对应的阈值就是大津法(OTSU算法)所求的阈值

    /* Applies adaptive threshold to grayscale image.
       The two parameters for methods CV_ADAPTIVE_THRESH_MEAN_C and
       CV_ADAPTIVE_THRESH_GAUSSIAN_C are:
       neighborhood size (3, 5, 7 etc.),
    */
    
    CVAPI(void)  cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value,
                                      int adaptive_method CV_DEFAULT(CV_ADAPTIVE_THRESH_MEAN_C),
                                      int threshold_type CV_DEFAULT(CV_THRESH_BINARY),
                                      int block_size CV_DEFAULT(3),
                                      double param1 CV_DEFAULT(5));

    src输入图像
    dst输出图像
    max_value表示最大值
    adaptive_method
    自适应阈值算法使用:CV_ADAPTIVE_THRESH_MEAN_C 或 CV_ADAPTIVE_THRESH_GAUSSIAN_C .
    threshold_type
    阈值类型:必须是CV_THRESH_BINARY或者CV_THRESH_BINARY_INV.
    block_size
    用来计算阈值的象素邻域大小: 3, 5, 7, …,block_size比较小的时候,相当于提取边缘
    param1
    与方法有关的参数,它是一个从均值或加权均值提取的常数,它可以是负数。
    对方法 CV_ADAPTIVE_THRESH_MEAN_C,先求出块中的均值,再减掉param1。
    对方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C ,先求出块中的加权和(gaussian),再减掉param1。

    区域分割
    图像按照相似性准则分成不同的区域,主要包括区域增长,区域分裂合并和分水岭等几种类型

    边缘分割
    通过边缘检测,即检测灰度级或者结构具有突变的地方,表明一个区域的终结,也是另一个区域开始的地方。
    这种不连续性称为边缘。不同的图像灰度不同,边界处一般有明显的边缘,利用此特征可以分割图像

    图像中边缘处像素的灰度值不连续,这种不连续性可通过求导数来检测到。
    对于阶跃状边缘,其位置对应一阶导数的极值点,对应二阶导数的过零点(零交叉点)。
    因此常用微分算子进行边缘检测。常用的:
    一阶微分算子有Roberts算子、Prewitt算子和Sobel算子、LoG算子,
    二阶微分算子有Laplace算子和Kirsh算子、Canny算子等。
    在实际中各种微分算子常用小区域模板来表示,微分运算是利用模板和图像卷积来实现。这些算子对噪声敏感,只适合于噪声较小不太复杂的图像。

    由于边缘和噪声都是灰度不连续点,在频域均为高频分量,直接采用微分运算难以克服噪声的影响。因此用微分算子检测边缘前要对图像进行平滑滤波。LoG算子和Canny算子是具有平滑功能的二阶和一阶微分算子,边缘检测效果较好

    边缘检测算法:
    滤波:边缘检测算法主要是基于图像强度的一阶和二阶导数,但导数的计算对噪声很敏感,因此必须使用滤波器来改善与噪声有关的边缘检测器的性能.
    增强:将邻域(或局部)强度值有显著变化的点突显出来.边缘增强一般是通过计算梯度幅值来完成的.
    检测:确定边缘,最简单的边缘检测判据是梯度幅值阈值判据.
    定位:边缘的位置、方位可在子像素分辨率上估计出来.

    CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
                             double threshold1, double threshold2,
                             int apertureSize=3, bool L2gradient=false );

    1、高斯平滑滤波器卷积降噪,默然采用size = 5的高斯内核
    2、运用一对卷积阵列 (分别作用于x和y方向)求导,Sobel内核大小3 X 3,计算梯度幅值和方向
    3、根据阀值、梯度幅值得出边缘

    Canny边缘检测算法
    一个多级边缘检测算法,普遍认为是边缘检测的最优算法,Canny使用滞后阈值,滞后阈值需要两个阈值(高阈值和低阈值)
    Canny使用两种不同的阈值分别检测强边缘和弱边缘,并且仅当弱边缘和强边缘相连时,才将边缘包含在输出图像中。因此不容易被噪声“填充”,更容易检测出真正的弱边缘

    原灰度图像: image single-channel 8-bit input image.
    输出图像 (支持原地计算,可为输入图像): edges output edge map; it has the same size and type as image
    低阈值的: threshold1 first threshold for the hysteresis procedure.
    高阈值的3倍 (Canny 推荐的 高:低 阈值比在 2:1 到3:1之间): threshold2 second threshold for the hysteresis procedure.

    //! applies generalized Sobel operator to the image
    CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
                             int dx, int dy, int ksize=3,
                             double scale=1, double delta=0,
                             int borderType=BORDER_DEFAULT );

    Sobel算子
    (对灰度渐变和噪声较多的图像处理效果较好。Sobel算子对于边缘定位比较准确)
    是一个离散微分算子 (discrete differentiation operator), 它用来计算图像灰度函数的近似梯度。
    通过像素点空间邻域内上下,左右相邻点的灰度加权运算,求取物体边缘(边缘是指一个物体与另一个物体的分界处,一般边缘内外处都会有灰度值上的差异)
    Sobel 算子结合了高斯平滑和微分求导, Scharr更准确地计算 3 X 3 核(Gx、Gy卷积因子)的导数
    X\Y两个方向求导(输入图像与卷积核Gx和Gy进行卷积)-> 图像的每一点,结合以上两个结果求出近似梯度 -> 定位梯度值大于邻域的相素,作为边缘
    ddepth: value as below
    CV_8U = 0,
    CV_8S = 1,
    CV_16U = 2,
    CV_16S = 3,
    CV_32S = 4,
    CV_32F = 5,
    CV_64F = 6,
    CV_USRTYPE1 = 7;

    展开全文
  • 分割与过分割

    千次阅读 2019-06-29 16:15:39
    分割与过分割含义——图像分割 我们在做图像分割时,分为我们需要的目标物和目标物意外的背景 分割后的图像中,前景目标物误分割为背景(即目标物没有分割完整)则为欠分割 反之,背景误分割为前景目标物则为过...
  • 前面的文章讲解了图像锐化和边缘提取技术,该篇文章将开始围绕图像分割进行讲解。图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。 本篇文章主要讲解基于理论的图像分割方法...
  • 图像分割—灰度阈值分割

    千次阅读 2019-08-14 11:39:55
    阈值分割概念图像阈值分割具有直观和易于实现的特点,在图像分割应用中占有重要地位。许多情况下,图像$f(x,y)$由暗对象和亮对象这两类具有不同灰度级的区域组成,如报纸和书本。这种图像的亮暗部分可以在直方图中...
  • Date: 2018.6.9 文章目录1、 参考2、分割字符串的三种方法2.1 str.split()2.2 re.split()2.3 str.partition() 1、 参考 ...2、分割字符串的三种方法...利用字符串函数split分割分割后返回的是分割部分的字符列表,但是
  • 语义分割分割常用网络

    千次阅读 2020-04-26 16:25:30
    语义分割 图像的语义分割是将输入图像中的每个像素分配一个语义类别,以得到像素化的密集分类。 一般的语义分割架构可以被认为是一个编码器-解码器网络。编码器通常是一个预训练的分类网络,像 VGG、ResNet,然后...
  • Matlab实现图像阈值分割

    万次阅读 多人点赞 2017-11-13 15:40:22
    使用matlab实现阈值分割,实现两种方法,一是人工选择阈值进行分割,而是自动选择阈值进行分割。操作步骤 1、 打开Matlab内容自带的coins.png图像。 2、 观察它的直方图。 3、 人工选定一个阈值,并进行分割。 4...
  • 图像分割与视频分割方法

    千次阅读 2019-05-12 12:15:54
    图像分割传统的图像分割方法1、基于阈值的图像分割单阈值分割局部阈值分割阈值的选取2、基于区域的图像分割区域生长区域分裂合并四叉树分解法3、基于边缘检测的图像分割结合特定工具的图像分割算法1、基于小波分析和...
  • JS字符串分割截取

    万次阅读 2019-06-30 09:08:56
    功能:把一个字符串按指定的分隔符分割存储到数组中。 例子: str="2018.12"; arr=str.split("."); //arr是一个包含"2018"和"12"的数组,arr[0]是2018,arr[1]是12。 2.函数:join() 功能:使用分隔符将一个...
  • 阈值分割与区域分割

    万次阅读 2017-01-02 13:22:51
    阈值分割我们曾在3.5节学习过灰度阈值变换的相关知识, 利用灰度阈值变换分割图像就称为阈值分割, 它是一种基本的图像分割方法。 阙值分割的基本思想是确定一个阈值, 然后把每个像素点的灰度值和阈值相比较,根据...
  • 图像分割

    万次阅读 2019-03-22 20:07:54
    图像分割是指将图像分成若干互不重叠的子区域,使得同一个子区域内的特征具有一定相似性,不同子区域的特征呈现较为明显的差异。 常用方法 1.基于阈值的分割方法 2.基于边缘检测的分割方法 3.基于区域的分割方法 4....
  • 这三者的区别请参考超像素、语义分割、实例分割、全景分割 傻傻分不清?简单来说: 1. 语义分割是最简单的,对每个像素做分类,比如说将这幅图像分为人和汽车。但是具体有三个人,无法对这三个人做具体区分。 注意...
  • 全卷积神经网络图像分割(U-net)-keras实现

    万次阅读 多人点赞 2017-04-17 20:36:34
    最近在研究全卷积神经网络在图像分割方面的应用,因为自己是做医学图像处理方面的工作,所以就把一个基于FCN(全卷积神经网络)的神经网络用 keras 实现了,并且用了一个医学图像的数据集进行了图像分割。...
  • 图像分割综述

    万次阅读 多人点赞 2019-07-09 22:03:48
    图像分割是计算机视觉研究中的一个经典难题,已经成为图像理解领域关注的一个热点,图像分割是图像分析的第一步,是计算机视觉的基础,是图像理解的重要组成部分,同时也是图像处理中最困难的问题之一。所谓图像分割...
  • CV之IS:计算机视觉之图像分割(Image Segmentation)算法的挑战任务、算法演化、目标检测和图像分割(语义分割/实例分割/全景分割)的对比 相关文章CV之IS:计算机视觉之图像分割(Image Segmentation)算法的简介、...
  • 文件分割

    千次阅读 2019-12-11 16:48:39
    将大文件分割为小文件 2.学习/操作 编程:php实现 1.小文件分割为多个子文件[[KB级别]] <?php $content = $_POST['file']; //如果是文件也要先读取,后分割. $arr = preg_...
  • 在计算机视觉中,图像分割是个非常重要且基础的研究方向。简单来说,图像分割(image segmentation)就是根据某些规则把图片中的像素分成不同的部分(加不同的标签)。 图像分割中的一些常见的术语有:superpixels...
  • 图像分割—基于区域的图像分割

    千次阅读 2019-08-17 10:40:40
    基于区域的分割是以直接寻找区域为基础的分割技术,实际上类似基于边界的图像分割技术一样利用了对象与背景灰度分布的相似性。大体上基于区域的图像分割方法可以分为两大类:区域生长法区域分裂与合并1 区域生长法...
  • 1998年以来,人工神经网络识别技术已经引起了广泛的关注,并且应用于图像分割。基于神经网络的分割方法的基本思想是通过训练多层感知机来得到线性决策函数,然后用决策函数对像素进行分类来达到分割的目的。这种方法...
  • 时空联合分割

    千次阅读 2021-03-20 05:39:57
    时空联合分割针对静态背景下的运动对象分割,采用时空联合的运动对象分割算法,即综合使用序列图像在空间域和时间轴上的信息进行分割,以基于时域运动信息的分割为算法的主体,而空间分割信息作为有益的补充对时域分割...
  • 实例分割与语义分割的区别

    千次阅读 2019-07-06 16:48:26
    实例分割 实例分割的基本思路:目标检测 + 语义分割 机器自动从图像中使用目标检测方法框出不同实例,然后用语义分割方法在不同区域内进行逐像素标记 ...
  • 语义分割(Semantic Segmentation)方法

    万次阅读 多人点赞 2019-01-02 18:04:09
    语义分割方面的资源:https://github.com/mrgloom/awesome-semantic-segmentation 1. 什么是语义分割 语义分割是当今计算机视觉领域的关键问题之一。从宏观上看,语义分割是一项高层次的任务,...
  • 计算机视觉的任务很多,有图像分类、目标检测、语义分割、实例分割和全景分割等,那它们的区别是什么呢? 1、Image Classification(图像分类) 图像分类(下图左)就是对图像判断出所属的分类,比如在学习分类中...
  • 原文地址:...图像的语义分割是将输入图像中的每个像素分配一个语义类别,以得到像素化的密集分类。虽然自 2007 年以来,...
  • 数据库的水平分割和垂直分割

    千次阅读 2019-06-11 12:16:47
    在数据库操作中,我们常常会听说这两个词语:水平分割和垂直分割。那么到底什么是数据库的水平分割,什么是数据库的垂直分割呢?本文我们就来介绍一下这部分内容。 1、水平分割: 按记录进分分割,不同的记录可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 198,946
精华内容 79,578
关键字:

分割