精华内容
下载资源
问答
  • 微生物学实验报告.doc

    2021-01-14 23:15:15
    微生物学实验报告 实验名称:用高倍显微镜观察叶绿体和细胞质流动 一、实验目的 1.初步掌握高倍显微镜的使用方法。 2.观察高等植物的叶绿体在细胞质基质中的形态和分布 二、实验原理 高等植物的叶绿体呈椭球状,...
  • 昆虫实验报告.doc

    2021-01-19 11:04:53
    昆虫实验报告 篇一:昆虫实习报告 一、实习目的 通过到野外采集昆虫并制成标本,掌握野外采集昆虫的方法、了解不同昆虫的生存环境。掌握昆虫的形态特征,学习昆虫的识别方法和种类、了解昆虫与植物病虫害的...
  • 微生物用高倍显微镜观察叶绿体和细胞质流动实验报告 实验名称:用高倍显微镜观察叶绿体和细胞质流动 一、实验目的 1.初步掌握高倍显微镜的使用方法。 2.观察高等植物的叶绿体在细胞质基质中的形态和分布 二、...
  • 梁毅雄 实验一:数字图像基本操作及灰度调整 实验二:数字图像的空间域滤波和频域滤波 实验三:图像分割与边缘检测 实验四:数学形态学及其应用
  • 大学生植物病理实习报告 在教师里永远也到真正的土地植物原理,必须要走到田地中去,参加实习,才能在实习中得到植物成长的原理。作为一名植物病理专业学生,在实验室的学习永远不能完全的了解植物,必须要走进...
  •  实验中需要控制变量,我们想了很久,奶源是一个很重要的问题,奶质和形态都能影响酸奶的味道,所以我们选取了控制奶源变量的酸奶制作研究性学习,探究选取哪一种奶源才会使自制酸奶口感更好。 二、活动目标 近几...
  • 本文报告了将71只长耳白兔制成实验性伤口,分别进行激光照射,着重进行形态学和组织学方面的探讨,结果发现 He-Cd 无效,He-Ne 和CO2。激光有效。初步认为 He-Ne 激光促进伤口愈合的机理可能是改善其血液、淋巴循环、...
  • 所包括的实验项目有:图像的灰度变换、图像的几何变换、空间域图像增强 、图像的傅立叶变换、图像增强——频域滤波、图像复原、形态学图像处理、图像分割。
  • 生物技术与应用专业野外实习报告 生物是一门实践性很强的学科,我们在经过了将近一年对动物和植物的理论学习后,野外实习也至关重要,它可以使我们更加有效地掌握和巩固课堂教学的基本理论知识和基本实验技能...
  • 最后通过横向形态学运算使类车牌区闭合,以有效地克服以往形态学结构元素难以随车牌尺寸变化自适应选取的问题;同时提出了根据场景实际情况,选用灰度调整和颜色来判别模块的观点。通过实际场景中大量车牌样本的验证...
  • GMM(高斯混合模型)的动态背景分割的实验报告以及源码,数据集。 另外用到了形态学操作与多通道的处理,提升了实验结果的性能。
  • GMM(高斯混合模型)的动态背景分割

    千次阅读 热门讨论 2019-11-13 14:19:10
    以下是GMM(高斯混合模型)的动态背景分割的实验报告以及源码,另外用到了形态学操作与多通道的处理,提升了实验结果的性能。 一.实验名称 基于混合高斯模型的动态背景分割 二.实验目的 探索如何对...

    以下是GMM(高斯混合模型)的动态背景分割的实验报告以及源码,另外用到了形态学操作与多通道的处理,提升了实验结果的性能。

    一.实验名称

    基于混合高斯模型的动态背景分割

     

    二.实验目的

    探索如何对Wavingtrees等具有动态背景的数据集进行有效的建模并分割,检测前景物体。

     

    三.实验原理

    3.1 前言

    时域中的同一个点的像素值看做是一个像素过程,由一组像素组成,如果这里只考虑灰度图的话,对于点x0y0 处于时间t 的像素历史值为

    其中I 代表着图像序列,由于各种因素,环境中的背景往往不是完全不变的,下图展示在wavingtrees中两个像素点随着帧数其像素值的变化。

             

     

                                                                               图3.1 像素值变化图

    从上图可以看出,我们在第一帧中选取了两个点,一个点坐标值为(11,14).位于较为远离树的位置,另一个点坐标值为(102,78)。位于树与人交叉的位置。从右上角与右下角的图表示像素值随着帧数的变化。横坐标为帧数,纵坐标为像素值的大小。可以明显的看出,随着时间的推移,即随着帧数的增加,像素点的值的分布较为分散,特别是前景与背景交叉的区域。所以单个模型,比如单个高斯模型难以适应这种场景。采用高斯混合模型就可以较好的适应这种变换。

    3.2 高斯混合模型

    3.2.1 背景建模

    (1)高斯模型定义

    鉴于由于背景环境的复杂变化,单个高斯模型难以适应,考虑对每个像素值序列X1,…,Xn 建立K 个高斯分布综合描述。当前像素值得到的概率密度函数由以下公式进行描述:

     

    是该点对应的高斯模型的最大数目, 是时间 时的第 个高斯模型的权重,即当前高斯模型对于该像素点对应的所有模型占得权重, 是时间 时的第 个高斯模型的期望, 是时间 时的第 个高斯模型的协方差矩阵, 代表高斯概率密度方程:

    考虑到程序的空间与时间复杂度, 的取值一般为3-5.而且协方差矩阵被简化为

    因为在这里我们假设RGB三通道的数据具有互相独立而且相同的方差。虽然有些不符合现实,但是在损失了一些精度的代价下减少了程序的时间复杂度。

    (2)训练过程

    这里先采用若干张图片进行训练,即更新每个响度点对应的高斯混合模型的个数,高斯模型的参数等。背景建模的算法流程图如下

                                                                                       图3.2 算法流程图

    在上图中,判断一个像素点是否服从高斯分布:像素值是否位于高斯分布的2.5倍标准差内。对于每个像素点对应的高斯模型,如果该像素值匹配到了某个高斯模型,则更新公式如下:

                     

     

     

    对于没有匹配到的高斯模型,其方差与期望不变,权重的更新按照上述公式。其中当像素点匹配了某个高斯模型的时候 值为1,否则值为0。

    如果该像素值与其对应的高斯模型都不匹配,则判断当前像素值的高斯模型个数是否已到达上限阈值K。

    1.如果达到的话,侧取权重与方差比值最低的那个高斯分布重新进行初始化。权重赋予一个较低的值,这个值在程序中取得0.05.方差赋值为一个较高的值,程序中取值为30.高斯分布的期望赋值为该像素点的值。

    2.如果没有达到的话。则新建一个高斯分布。初始化步骤同上。权重赋予一个较低的值,这个值在程序中取得0.05.方差赋值为一个较高的值,程序中取值为30.高斯分布的期望赋值为该像素点的值。

    当前像素值与其对应的高斯模型匹配结束之后,把该像素值对应的高斯模型按照权重与方差的比例降序排列,接着对所有高斯模型对应的权重进行归一化。

     

    3.2.2 前景检测

    每个像素值对应的各个高斯分布的参数会一直发生改变,当一个物体趋于静止的时候,对应的像素高斯分布的方差会趋于更小,其对应的权重会趋于变得更大,相对于一个运动的物体,他一般不会匹配到像素对应的高斯模型,运动的物体会让高斯模型的方差变得更大,权重变得更低。

    我们按照高斯模型的权重与方差的比值进行降序排列,由阈值T(程序中取值为0.7)选出B个高斯分布作为当前像素判断是否属于背景的模型:

                        

    如果一个新的像素值服从该B 个高斯模型中的某一个,我们就认为该像素属于背景。但是如果该像素服从某个高斯分布,但是该高斯分布位于该B 个高斯模型之后,该像素仍然会被判定为前景。T的取值不宜过大,否则会产生一个多峰分布模型,背景模型如果是单峰值的话,会选出一个可能性最高的高斯分布。

    3.2.3 形态学处理

    背景往往不是一直不变的,有些背景可能会一直处于一种细微变化的状态,比如本实验给出的数据集wavingtrees,背景中的树一直处于在摇晃的状态,所以在检测前景的时候总是会把一些树的枝丫之类识别为前景。

    为了去除一些被误识别为前景的树枝,考虑采用以下三种形态学操作。

    (1)中值滤波:中值滤波常被用来处理椒盐噪声,这里的树枝可以看成是前景中的椒盐噪声。中值滤波的原理就是将当前像素值替换为周围领域像素值的中值。

    (2)腐蚀:在周围都是背景的情况下,被误识别为前景的树枝可以经过腐蚀操作进行消除,但是这个操作会对前景中的人轮廓有一定的影响。

    (3)膨胀:由于中值滤波或者腐蚀操作会对前景中的人造成一定的影响,即会让人的轮廓出现空洞,所以可以采用膨胀操作在一定程度上减弱这个影响。

    3.2.4 三通道的考虑

    这里运用的三通道其实就是在三个通道上进行背景建模与前景检测。

    背景建模:每个通道的像素点都会建立数目最多为K个的高斯模型。每个通道的建模过程跟3.2.1小节与3.3.2小节描述的一样。

    前景检测:原来是灰度图的单通道进行判断,其接受为前景就认为是前景,而现在对于三通道就需要三个通道都认为是前景才认为当前像素是前景。

    四.实验结果

    本实验采用在线训练,在线测试的方式,为了对比3.2小节描述的形态学操作与三通道的有效性。实验中做了多组对比实验。

    4.1 三通道运用

    不采用任何的形态学操作,运用RGB三通道与只利用单通道的效果如下图4.1所示。

                                                                 

                                                                                 (a)单通道            (b)多通道

                                                                                       图4.1 rgb效果对比图

    在图4.1中,左边的图是仅仅考虑单通道的时候第247帧的效果,右边的图是考虑三通道之后第247帧的效果。可以明显看出考虑了三通道之后,前景中的人轮廓显得更加丰满了,而对于单通道的情况,人的轮廓中就会存在许多的空洞区域。原因就在于三通道的时候是每个通道都接受为前景才认为是前景,从而是前景的判断更加准确合理。

    4.2 形态学操作

    实验中考虑了两种形态学组成操作对图像进行处理。

    在实验中我们对比了在考虑三通道的情况下,采用开运算,即先腐蚀后膨胀;与先进行中值滤波,在进行膨胀的效果。如下图4.2所示。

                                                              

                                                                        (a)开运算        (b)中值滤波与膨胀

                                                                               图4.2 形态学操作对比图

    在上图4.2中,左边的图是第247帧采用了开运算的效果,其中核为十字架形,大小为3;右边的图为先进行中值滤波,再采用膨胀操作之后的效果,其中中值滤波的核大小为7,膨胀操作的核大小为3。从实验结果可以看出。直接利用开运算没有先进行中值滤波,再进行膨胀的效果好,前者会使人的轮廓产生一些空洞。这证明了中值滤波的效果比腐蚀的效果要好。

    当形态学操作采用先进行中值滤波,后进行膨胀操作之后,对比了膨胀不同的核大小对于结果的影响。仍然采用第247帧的效果对比。

                                                              

                                                                    (a)核大小为3          (b)核大小为5

                                                                                         图4.3

    在图4.3中,左图表示膨胀的核大小为3,右边的图表示核的大小为5。可以看出当采用核大小为5的时候,人的轮廓显得更加丰满了。证明了核大小为5比3要好。

    该实验的最后结果就是采用先进行中值滤波,后进行膨胀操作之后的效果。其中中值滤波的核大小为7,膨胀操作的核大小为5。

    最后我们对比了opencv自带的createBackgroundSubtractorMOG2函数处理的效果与本实验最后得到的效果图。如下图4.4所示。

                                              

                                                          (a)本实验结果      (b)opencv(MOG2)      (c)groundtruth

                                                                                            图4.4

    在图4.4中,仍然是展示第247帧的效果。左边的图是本实验最后得到的最好结果图,中间的图是opencv自带的MOG2函数得到的效果图。右边的图是groundtruth。可以看出本实验得到的效果图已经和后面两张图非常类似,这就证明了本实验的算法的有效性。不过其实也可以看出,由本实验得出的图由于采用了膨胀操作,导致人的轮廓有些略大。

    五.实验总结

    建立高斯混合模型可以较为有效的分割出背景与前景。得到了像素值在时间域上的拟合分布情况。运用高斯混合模型在wavingtrees上取得了较好的结果。

    实验中运用的形态学操作一定程度上消除了被检测为前景的树,三通道在一定程度上消除了被误检测为背景的人的轮廓,使得人的轮廓更加的清晰。这都证明了实验中形态学操作与三通道运用的有效性。

    但是从实验中也可以看出高斯混合模型对于这种动态背景还是不鲁棒的,仅仅是wavingtrees中背景中的树的轻微晃动,就会出现把树误检测为前景的情况,将前景中的人误检测为背景。这些情况在没有添加形态学操作与三通道的时候尤为明显。所以可以推断当背景发现较为明显的变化时,比如物体突然移动,光照突然变化。高斯混合模型都是无法适应这种变换的。

     

    实验报告以及完成源码,数据集:https://download.csdn.net/download/breeze_blows/11975860

    核心源代码:

    import cv2
    import numpy as np
    import glob
    
    GMM_MAX_COMPONT = 5
    SIGMA = 30
    gmm_thr_sumw = 0.6
    train_num = 2
    WEIGHT = 0.05
    T = 0.7
    alpha = 0.005
    eps = pow(10, -10)
    channel = 3
    GMM_MAX_COMPONT = GMM_MAX_COMPONT
    m_weight = [[] for i in range(GMM_MAX_COMPONT*channel)]#怎么先对numpy初始化为一维数组,后续在对每个元素重新复制为数组呢
    m_mean = [[] for i in range(GMM_MAX_COMPONT*channel)]
    m_sigma = [[] for i in range(GMM_MAX_COMPONT*channel)]
    m_fit_num = None
    
    def init(img):
        row, col, channel = img.shape
        global m_fit_num
        for i in range(GMM_MAX_COMPONT*channel):
            m_weight[i] = np.zeros((row, col), dtype='float32')
            m_mean[i] = np.zeros((row, col), dtype='float32')
            m_sigma[i] = np.ones((row, col), dtype='float32')
            m_sigma[i] *= SIGMA
    
        m_fit_num = np.zeros((row, col), dtype='int32')
    
    def train_gmm(imgs):
        row, col, channel = imgs.shape
        B, G, R = cv2.split(imgs)
        m_mask = np.zeros((row,col), dtype=np.uint8)
        m_mask[:] = 255
        for i in range(row):
            for j in range(col):
                cnt = 0
                for c, img in enumerate((B,G,R)):
                    # img = imgs[:,:,c]
                    # img = B.copy()
                    num_fit = 0
                    for k in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                        if m_weight[k][i][j] != 0:
                            delta = abs(img[i][j]-m_mean[k][i][j])
                            if float(delta) < 2.5*m_sigma[k][i][j]:
                                m_weight[k][i][j] = (1-alpha)*m_weight[k][i][j] + alpha*1
                                m_mean[k][i][j] = (1-alpha)*m_mean[k][i][j] +alpha*img[i][j]
                                m_sigma[k][i][j] = np.sqrt((1-alpha)*m_sigma[k][i][j]*m_sigma[k][i][j]+alpha*(img[i][j]-m_mean[k][i][j])*(img[i][j]-m_mean[k][i][j]))
    
                                num_fit += 1
    
                            else:
                                m_weight[k][i][j] *= (1-alpha)
    
                    for ii in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                        for jj in range(ii + 1, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                            if (m_weight[ii][i][j] / m_sigma[ii][i][j]) <= (m_weight[jj][i][j] / m_sigma[jj][i][j]):
                                m_sigma[ii][i][j], m_sigma[jj][i][j] = m_sigma[jj][i][j], m_sigma[ii][i][j]
                                m_weight[ii][i][j], m_weight[jj][i][j] = m_weight[jj][i][j], m_weight[ii][i][j]
                                m_mean[ii][i][j], m_mean[jj][i][j] = m_mean[jj][i][j], m_mean[ii][i][j]
    
                    if num_fit == 0:
                        if 0==m_weight[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j]:
                            for kk in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                                if (0 == m_weight[kk][i][j]):
                                    m_weight[kk][i][j] = WEIGHT
                                    m_mean[kk][i][j] = img[i][j]
                                    m_sigma[kk][i][j] = SIGMA
                                    break
                        else:
                            m_weight[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j] = WEIGHT
                            m_mean[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j] = img[i][j]
                            m_sigma[c*GMM_MAX_COMPONT+GMM_MAX_COMPONT-1][i][j] = SIGMA
    
                    weight_sum = 0
                    for nn in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                        if m_weight[nn][i][j] != 0:
                            weight_sum += m_weight[nn][i][j]
                        else:
                            break
    
                    weight_scale = 1.0/(weight_sum+eps)
                    weight_sum = 0
                    for nn in range(c*GMM_MAX_COMPONT, c*GMM_MAX_COMPONT+GMM_MAX_COMPONT):
                        if m_weight[nn][i][j] != 0:
                            m_weight[nn][i][j] *= weight_scale
                            weight_sum += m_weight[nn][i][j]
                            if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                                cnt += 1
                                break
                            if weight_sum > T:
                                if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                                    cnt += 1
                                break
                        else:
                            break
    
    
                if cnt == channel:
                    m_mask[i][j] = 0
    
        # cv2.imshow('img_gray', img)
        m_mask = cv2.medianBlur(m_mask, 7)
        # kernel_e = np.ones((3, 3), np.uint8)
        # m_mask = cv2.erode(m_mask, kernel_e)
        kernel_d = np.ones((5, 5), np.uint8)
        m_mask = cv2.dilate(m_mask, kernel_d)
        # element = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))  # 形态学去噪
        # m_mask = cv2.morphologyEx(m_mask, cv2.MORPH_OPEN, element)  # 开运算去噪
        return m_mask
        # cv2.imshow('img_mask', m_mask)
        # cv2.waitKey(1)
    
    def test_img(imgs):
        row, col, channel = imgs.shape
        B, G, R = cv2.split(imgs)
        m_mask = np.zeros((row, col), dtype=np.uint8)
        m_mask[:] = 255
        for i in range(row):
            for j in range(col):
                cnt = 0
                for c, img in enumerate((B, G, R)):
                    weight_sum = 0
                    for nn in range(c * GMM_MAX_COMPONT, c * GMM_MAX_COMPONT + GMM_MAX_COMPONT):
                        if m_weight[nn][i][j] != 0:
                            weight_sum += m_weight[nn][i][j]
                            if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                                cnt += 1
                                break
                            if weight_sum > T:
                                if abs(img[i][j] - m_mean[nn][i][j]) < 2 * m_sigma[nn][i][j]:
                                    cnt += 1
                                break
                        else:
                            break
    
                if cnt == channel:
                    m_mask[i][j] = 0
    
        m_mask = cv2.medianBlur(m_mask, 7)
        kernel_d = np.ones((5, 5), np.uint8)
        m_mask = cv2.dilate(m_mask, kernel_d)
    
        return m_mask
    
    
    import time
    
    if __name__ == '__main__':
        data_dir = 'D:/images/'
        file_list = glob.glob('D:/images/b*.bmp')
        i = -1
        for file in file_list:
            # print(file)
            i += 1
            img = cv2.imread(file)
            # img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
            if i == 0:
                init(img)
    
            if i <= 200:
                t1 = time.time()
                m_mask = train_gmm(img)
                # cv2.imwrite("./rgb_morphologyEx3_MORPH_ELLIPSE/{}.jpg".format(i), m_mask)
                t2 = time.time()
                print(t2-t1)
            if i == 286:
                j = 0
                for temp_file in file_list:
                    temp_img = cv2.imread(temp_file)
                    m_mask = test_img(temp_img)
                    cv2.imwrite("./rgb_mb7_dila5_train200/{:0>5d}.jpg".format(j), m_mask)
                    j += 1
    
    

    参考:

    https://blog.csdn.net/zouxy09/article/details/9622401

    https://blog.csdn.net/lwx309025167/article/details/78513437#commentBox

    展开全文
  • 由于最近课业繁忙,作业太多,我就直接把做好的实验报告搬过来了。一、实验名称:图像处理二、实验目的:1.使学生通过分析图片,采用合适的图像增强方法获得较为清晰的图片,进而加强对各 种图像增强方法的了解;2....

    由于最近课业繁忙,作业太多,我就直接把做好的实验报告搬过来了。

    一、实验名称:图像处理

    二、实验目的:

    1.使学生通过分析图片,采用合适的图像增强方法获得较为清晰的图片,进而加强对各 种图像增强方法的了解;

    2.能够利用二值形态学消除干扰,获得目标图像;

    3.能够了解各种图像增强方法中参数的选择对处理结果的影响;

    4.完成规定图像的处理并要求正确评价处理结果,能够从理论上作出合理的解释。

    三、实验内容:

    1.选用合适的图像增强方法对以下给定图像进行增强操作以获取清晰图像;

    2.对步骤1处理后的图像(c)进行阈值处理,获得二值图像,并对其进行形态学分析,提取 有用信息区域(即只剩下字母和数字区域)。

    四、实验步骤

    4.1运行环境

    使用windows系统,以python36为编程语言,opencv以及PIL为图像处理框架,tensorflow&keras的深度学习框架进行图像去模糊复原。

    4.2实验步骤

    4.2.1 图片1

    针对图片1,原图整体效果偏灰,边缘信息较为明显,仅凭肉眼可以大致看出图片主体是两架飞机的形态。原图效果如下:

    3375405b80053bc89e2e6bb62593f9b9.png
    图4.1 主体为两架飞机的不清晰图片

    由此可以从对比度入手,提高图片的对比度,将飞机与天空中的背景区尽可能的分开。实验采取了自适应直方均衡化的方法,对比直接均衡化方法,自适应直方图均衡化方法在效果上更具有针对性,通过计算图像的局部直方图,重新分布图像的亮度从而改变图片对比度。均衡化的结果如下图所示:

    67206fd9c2aaa6386cbc2e2b4197a1fd.png
    图4.2 自适应均衡化后的图像1

    由图4.2可见,飞机的相对于背景的对比度有较大的改善,但是背景中的黑色颗粒同样被提升了。实际上图4.2的对于图片主体飞机来说清晰度已经很高了,但为了减小黑色颗粒对于图片的影响,可以采用消噪处理。由于滤波器的模糊是针对白色噪声的,并且经过实验后,效果确实不理想,并且会使图片更加不清晰,所以采用二值形态学中的闭运算,因为闭运算是针对图像中白色区域而言的,作用是将图像中白色区域中的黑色子区域填充上。可以采用闭运算的方法减小图像中黑色的影响。处理结果如下:

    c50a5b30420eba352e5762794c70542f.png
    图4.3 经均衡化和闭运算后的图像1

    由图4.3可见,闭运算后的图像仍保留了原来的对比度,黑色颗粒的影响减轻了许多。代码如下:

    from utils import *
    #读入原始图像
    img=cv2.imread('image1.bmp',0)
    # 直接均衡化
    # imgEqualizeHist = cv2.equalizeHist(img)
    # 自适应直方均衡化
    clahe = cv2.createCLAHE(clipLimit=64.0, tileGridSize=(8, 8))
    imgCLAHE = clahe.apply(img)
    # 闭运算
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) # 定义结构元素
    closing = cv2.morphologyEx(imgCLAHE, cv2.MORPH_CLOSE, kernel) 
    titles = ['原图', '自适应直方图均衡', '闭运算']
    images = [img, imgCLAHE, closing]
    out(titles, images)

    4.2.2 图片2

    针对图片2,图片为医学图片中的骨骼图,首先图片对比度不高,头颅内的光线模糊,双臂的亮度太低,器官的对比度不够。原图效果如下:

    52d8354ba4b7666a1c262fbc111c2515.png
    图4.4 医学骨架的不清晰图片

    由于医学图像一般来说占用存储空间较大,需要进行数据压缩才能便于后期处理。而且仅凭空域的处理并不能有选择性的调整图像的对比。此选用频域的处理方法同态滤波器增强对比度。同态滤波器就是将图像信号在频域上进行处理,加强高频衰减低频从而加强对比度。使用同态滤波器处理后的图像如下:

    fc9a97b5a8daab9571f42a6312dd9bcc.png
    图4.5 同态滤波器处理后的医学骨架图

    由图4.5可见,处理过后骨架、关节的一些细节变得很明显,但是双臂的对比度依然没有得到加强,可能的原因是同态滤波器的参数并没有适配到双臂的范围。但是参数扩大范围会让骨架及关节的效果被白化,效果十分不好。所以需要采用其他方式进行二次对比度提升,继续采用自适应直方图均衡化。对比度加强后的效果如下图所示:

    c369fd6e8125bb009c9f61a976545d14.png
    图4.6 两项对比度加强后的医学骨架图

    由图4.6可见,自适应直方均衡后的图像依旧保留了同态滤波器处理后的身体中部的对比度,而且在双臂的骨骼对比度也得到了加强,使图片变得非常清晰。

    处理代码如下:

    from utils import *
    # Homomorphic filter class
    class HomomorphicFilter:
        Attributes:
            a, b: Floats used on emphasis filter:
                H = a + b*H
        """
        def __init__(self, a=0.5, b=1.5):
            self.a = float(a)
            self.b = float(b)
    
        # Filters
        def __butterworth_filter(self, I_shape, filter_params):
            P = I_shape[0] / 2
            Q = I_shape[1] / 2
            U, V = np.meshgrid(range(I_shape[0]), range(I_shape[1]), sparse=False, indexing='ij')
            Duv = (((U - P) ** 2 + (V - Q) ** 2)).astype(float)
            H = 1 / (1 + (Duv / filter_params[0] ** 2) ** filter_params[1])
            return (1 - H)
    
        def __gaussian_filter(self, I_shape, filter_params):
            P = I_shape[0] / 2
            Q = I_shape[1] / 2
            H = np.zeros(I_shape)
            U, V = np.meshgrid(range(I_shape[0]), range(I_shape[1]), sparse=False, indexing='ij')
            Duv = (((U - P) ** 2 + (V - Q) ** 2)).astype(float)
            H = np.exp((-Duv / (2 * (filter_params[0]) ** 2)))
            return (1 - H)
    
        # Methods
        def __apply_filter(self, I, H):
            H = np.fft.fftshift(H)
            I_filtered = (self.a + self.b * H) * I
            return I_filtered
    
        def filter(self, I, filter_params, filter='butterworth', H=None):
            #  Validating image
            if len(I.shape) is not 2:
                raise Exception('Improper image')
    
            # Take the image to log domain and then to frequency domain
            I_log = np.log1p(np.array(I, dtype="float"))
            I_fft = np.fft.fft2(I_log)
    
            # Filters
            if filter == 'butterworth':
                H = self.__butterworth_filter(I_shape=I_fft.shape, filter_params=filter_params)
            elif filter == 'gaussian':
                H = self.__gaussian_filter(I_shape=I_fft.shape, filter_params=filter_params)
            elif filter == 'external':
                print('external')
                if len(H.shape) is not 2:
                    raise Exception('Invalid external filter')
            else:
                raise Exception('Selected filter not implemented')
    
            # Apply filter on frequency domain then take the image back to spatial domain
            I_fft_filt = self.__apply_filter(I=I_fft, H=H)
            I_filt = np.fft.ifft2(I_fft_filt)
            I = np.exp(np.real(I_filt)) - 1
            return np.uint8(I)
    import cv2
    image = cv2.imread('image2.jpg', 0)
    # 同态滤波器
    homo_filter = HomomorphicFilter(a=0.3, b=2.0)
    filtered_image = homo_filter.filter(I=image, filter_params=[0.05, 25])
    # 自适应直方均衡
    clahe = cv2.createCLAHE(clipLimit=20.0, tileGridSize=(3, 3))
    imgCLAHE = clahe.apply(filtered_image)
    # equalize_image = cv2.equalizeHist(filtered_image)
    titles = ['原图', '同态滤波', '自适应直方均衡']
    imgs = [image, filtered_image, imgCLAHE]
    out(titles=titles, imgs=imgs)
    

    4.2.3 图片3

    针对图像3,图像主体是车牌,加入了椒盐噪声的影响,并且图像的对比度很小。考虑到如果先提高对比度在进行消噪,噪声可能会淹没在图像中,在进行消噪效果会不明显。所以采用先消噪再加强对比度的方式。这里消噪选用中值滤波器进行。处理后的效果如下图所示:

    9950ba331feeab1668b31f4f8fdab709.png
    图4.7 中值滤波消噪后的效果图

    同样,选择自适应直方均衡方式对消噪后的图像提高对比度,效果图如下:

    1f64a44ac8a328cce4707e4ac183ddab.png
    图4.8 加强对比度后的效果图

    由图4.8可见,车牌的文字变得很清晰了,可以对图像进行二值化处理,得到更清晰的车牌号。效果如下:

    8955e82314c86707c9008262e0ea11fa.png
    图4.9 二值化后的效果图

    由图4.9可见,二值化后的图像纹理轮廓变得清晰,边缘相对于文字来说较细,想要消除边缘的影响,可以将黑色轮廓边缘视为白色区域内的噪点,需要进行闭运算操作进行处理。处理后的效果如下:

    06acbdf150272cb5196792d6e36dd580.png
    图4.10 闭运算后的效果图

    由图可见,通过闭运算操作后,图像确实有了良好的改进,但是并没能实现完全的消除掉除文字之外所有边缘的干扰。处理流程仍需改进。处理代码如下:

    from utils import *
    image = cv2.imread('image3.tif', 0)
    # 中值滤波
    img_median = cv2.medianBlur(image, 5)
    # 自适应均衡化
    clahe = cv2.createCLAHE(clipLimit=64.0, tileGridSize=(8, 8))
    imgCLAHE = clahe.apply(img_median)
    img_binary = binary = cv2.adaptiveThreshold(imgCLAHE, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY, 25, 10)
    # img_erode = cv2.erode(img_binary, np.ones((3,3), np.uint8))
    # img_dilation = cv2.dilate(img_erode, np.ones((3,3), np.uint8))
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 4)) # 定义结构元素
    closing = cv2.morphologyEx(img_binary, cv2.MORPH_CLOSE, kernel) # 闭运算
    titles = ['原图', '中值滤波','自适应直方均衡','二值化','闭运算']
    imgs = [image, img_median,imgCLAHE, img_binary, closing]
    out(titles, imgs, rows=2)

    4.2.4 图片4

    针对图片4,图片主体是深蓝色布景中的橄榄球。由于图像为彩色图,橄榄球主体为红色,颜色的对比度很大,所以不必从对比度方面考虑。图像不清晰的原因主要是模糊,而且边缘细节不够强,锐度不够。

    首先对图像进行去模糊处理,但是由于python的所有关于图像处理的库都不具有去模糊的操作,所以造成比较大的麻烦。找到了现有的深度学习再图像模糊修复的项目,并对其进行了研究与应用。项目地址如下:

    RaphaelMeudec/deblur-gangithub.com
    7e7f80415f8ef99b04cfdfce158c68ee.png

    , 相关论文:DeblurGAN: Blind Motion Deblurring Using Conditional Adversarial Networks

    https://arxiv.org/pdf/1711.07064.pdfarxiv.org

    ,模型结构如下:

    db9fd529576dd90d0fd9ae8007714da9.png
    图4.11 去模糊模型结构图

    大致的思路就是利用卷积神经网络的提取图像物体的结构化的细节特征的能力,通过残差层Resblock获取到在当前层所能获取的最好细节特征,对这些细节特征进行重新编码,重新排布,最终获得一张清晰的图像。由于采用了GAN生成式网络,所以同时还要训练一个监督者网络,两个网络同时训练,生成的图像效果逼真。由于深度网络模型输出的图像尺寸有限制,要求(256,256),所以还要对去模糊的图像进行尺寸调整。处理后的图像效果如下:

    c7d116266d5d07a076fef26ad63be46d.png
    图4.12 去模糊和尺寸调整后的效果图

    由图4.12可见,模型去模糊的效果还算令人满意。

    但为了得到更加清晰的图片,还可以从颜色的丰富度入手,也就是可以使用增强细节的滤波器,大致的效果就是亮色更亮暗色更暗,从一定程度上来说,增强的效果相对主观(和显示器的质量也有关系,实验时从两个屏幕观察的效果不同)。

    最后为了使橄榄球上的文字也能变得更清晰,采用了边缘锐化的滤波器处理。

    f6018c361af890cae03eeefcafb964a7.png
    图4.13 细节增强和边缘锐化后的效果图
    图4.13 细节增强和边缘锐化后的效果图

    由图4.13可见,细节增强后(在实验时的显示器观察),橄榄球右侧的过度曝光有了明显的改善,亮度变得相对均匀,文字花纹的颜色也更深一些。经边缘锐化后,虽然没能使得图像清晰度提高太多,但是橄榄球白色区域以及文字花纹都变得立体了很多,文字的辨识度和文字之间的区分度也有了一定的提高。代码如下:

    # 改动的去模糊模型的代码
    def deblur(image_path):
        data = {
            'A_paths': [image_path],
            'A': np.array([preprocess_image(load_image(image_path))])
        }
        x_test = data['A']
        g = generator_model()
        g.load_weights('generator.h5')
        generated_images = g.predict(x=x_test)
        generated = np.array([deprocess_image(img) for img in generated_images])
        x_test = deprocess_image(x_test)
    
        for i in range(generated_images.shape[0]):
            x = x_test[i, :, :, :]
            img = generated[i, :, :, :]
            # output = np.concatenate((x, img), axis=1)
            im = Image.fromarray(img.astype(np.uint8))
            return im
    
    from utils import *
    from PIL import Image,ImageFilter
    image = Image.open('image4.tif')
    
    size = np.asarray(image).shape[:2]
    debluered = Image.open('4.tif').convert('RGB')
    imgResize = debluered.resize((size[-1], size[0])) # 尺寸调整
    
    argue = imgResize.filter(ImageFilter.DETAIL)  # 细节增强
    enhaunse = argue.filter(ImageFilter.SHARPEN)  # 锐化
    titles = ['原图', '去模糊', '尺寸调整', '细节增强', '边缘锐化']
    imgs = [image, debluered, imgResize, argue, enhaunse]
    out(titles=titles, imgs=imgs, rows=2)

    五、实验结果及讨论:

    5.1分析与对比

    针对图像一,若使用直方图均衡的方法而不是自适应直方均衡,处理之后虽然也很清晰,但飞机主体光线的明暗变化不是很自然, 飞机尾部的细节全部消失。这并不能达到要求。

    45e5db3e171cc95044999bc936a337dc.png
    图5.1 采用直接直方图均衡化的效果图

    下面对采用自适应均衡化的方法的不同参数处理的效果进行比较:其中第一张图是最终采用的参数。

    3c6c90add7619728fdd561fe62191798.png
    图5.2 采用直接直方图均衡化的效果图

    由图可见,第3张图的效果最差;第2张的黑色颗粒噪点较少但是右侧小飞机的相对于背景的对比度弱;第4张稍微有些模糊,背景上有虚化现象;5,6两图效果近似,仅从视觉上来看和1区分度不大。

    针对图片二,若不采用同态滤波器提高对比度,而直接采用自适应直方均衡化提高对比度,骨骼的细节明显不如加了同态滤波器的方法,肋骨及关节的细节也出现了区分度不大的情况。头骨处同样模糊不清。所以使用同态滤波器作为第一步处理效果更好。

    f8d5735985cab497b306a941eee524f6.png
    图5.3 不使用同态滤波器处理的效果图

    下面针对同态滤波器的阈值参数进行调整并对比,对比结果如下图所示:

    29a17d73c274a313f6fc8ccd821e2ceb.png
    图5.4 同态滤波器不同阈值参数处理的效果图

    由图5.4可见,2和3变化最为明显,说明该医学图像的阈值主要是由阈值下界决定,由图1和4可知大部分白色在0.05~0.5的范围内,对这部分区域进行对比度加强即可获得较为清晰的图像。此处并没有进行均衡化的参数对比。

    针对图片三,对最后一步进行了闭运算、开运算、腐蚀与膨胀四种操作的对比

    0335a91bcd4f7022a421c7b0d3df5cbb.png
    图5.5 四种操作处理的对比效果图

    由图5.5可见,由于闭运算能够消除掉白色区域中的黑色小区域,闭运算处理后的结果较其他三种的效果好,开运算与膨胀操作效果近似,腐蚀将黑色区域加粗,所以文字及其他不需要的边缘也都被加粗,所以效果最差。

    类似的,对于开运算结构元素的窗口尺寸进行了效果对比,效果对比如下:

    28c6c5f36f20e3322a4f42035a20052f.png
    图5.6 六种窗口尺寸参数对比效果图

    由图5.6可见,图2和3由于窗口尺寸太小,并不能对黑色的边缘产生太大的影响,所以效果不好。图4中

    的窗口大小似乎不仅对于黑色的边缘效果显著,相应的也把我们所需要的车牌号的文字也隐去了一些,还好实在可接受的范围内。如果为了彻底的清除除车牌号外的一切信息,实际上图4效果比图1更好。图5和图6几乎看不到太多有效信息。

    针对图片四,由于去模糊的方式使用已经训练好的模型进行操作的,所以无法对模型参数进行调整,这里选择使用RGB与YCbCR颜色模型进行对比,对比效果如下:

    54431646871bd16eae76e9654a81b761.png
    图5.7 RGB与YCbCr模型下的处理效果对比图

    经对比发现,两种颜色模型下处理得到的结果几乎看不到任何区别。

    5.2遇到的问题

    1.由于python的 图像处理库有很多,如python-opencv、PIL等,opencv在读取图片时与其他的顺序都不一样,是以“BGR顺序”读取的。这样在多种模块混合使用的情况下就会导致显示的颜色出现错误。

    2.PIL读取图片的格式,会将图片矩阵进行转置,导致矩阵的shape无法匹配。而且当PIL读取彩色图片时,会默认以RGBA模式读取,也就是带了8位的透明度。

    5.3心得与体会

    通过本次实验,对图像处理有了初步的了解。

    1. 明确了消噪与去模糊是不同的概念;

    2. 知道了如何通过空域、频域的方式提升图片对比度;

    3. 了解了如何通过卷积核使得图像变得平滑,噪声减少;

    4. 初步了解了深度学习领域中去模糊的方法以及模型结构;

    5. 了解了PS软件等图像处理软件腐蚀、膨胀、开闭运算的概念以及运算过程。

    6. 对opencv、PIL的操作有了进一步的认识,了解了两者在图像处理的差异,在混合使用过程中需要注意的一些问题。

    展开全文
  • opencv中基础知识

    2017-04-06 11:13:03
    最近看完了浅墨的opencv入门,感觉有些地方理解的不是很深,尤其是对形态学的操作。 在一次实验组会议报告上,导师建议我先去了解一下二值细化骨架提取方法,在查阅了很多资料后,完全不知道怎么弄。毕竟编程能力...

    引用块内容http://lib.csdn.net/article/opencv/42000
    http://lib.csdn.net/article/opencv/61257
    最近看完了浅墨的opencv入门,感觉有些地方理解的不是很深,尤其是对形态学的操作。
    在一次实验组会议报告上,导师建议我先去了解一下二值细化骨架提取方法,在查阅了很多资料后,完全不知道怎么弄。毕竟编程能力差的孩子。然后就看了一些代码,也是似懂非懂,运行起来也是各种问题。解决不了,就看了细化原理,原来也是对像素的操作。只不过是一种迭代形式的,毕竟计算机最擅长的就是迭代嘛!
    二值细化也就是用模板对图像进行卷积操作(大概是这个意思吧,姑且这么理解),然后我就想到了腐蚀操作,了解了腐蚀操作原理,应该也就能理解二值细化骨架提取操作了吧。没想到,平常用的腐蚀内核三种形式,Rect,Cross,Ellipse,其实可以自己设计内核的。而且不同的内核去形式去卷积图像,得到的效果图也不一样。
    对像素的两种操作方式:at的操作很容易定位,就跟操作一个普通的二维数组一样,如img.at(i, j)[0] = 255;//对于蓝色通道进行操作;
    另一种:通过指针,uchar *pointer = img.ptr(i)
    for(int j = 0;j< cols;j++)
    {
    //pointer[j] = 255;//对蓝色通道进行操作
    //pointer[j+1] = 255;//对绿色通道进行操作
    pointer[j+2] = 255;//对红色通道进行操作
    }
    图像的数据以及图像在Mat中的存放格式的,就是我们上面那个彩色图像的存放示意图中的格式,这里把彩色图像中的一个像素点分成三份,每一份都是uchar类型,因此我们这里不需要使用Vec3b数据类型。把彩色图像看成一个rows * (cols * channels)的二维数组进行操作,其中的每个元素的类型都是uchar类型。这里需要注意的是j += 3是因为我们按照一个像素点进行操作,而一个像素点在这里面又被分成三份,因此需要j += 3,如果是灰度图像则直接j++即可
    熟悉了几个变量,Mat类中用的比较少的几个变量和函数,step1(),step[],size,elemSize和elemSize1。
    step1(i)表示的是Mat中的每一维的通道数;
    step[i]表示的是Mat中的每一维的大小,以字节为单位;
    size[i]表示的是Mat中元素的个数;
    elemSize()表示的是每个元素的大小 ,以字节为单位;
    elemSize1()表示的一个元素中每个通道的大小,以字节为单位。

    而step[i]表示的是每一维中的大小,以字节计数,在彩色图像中一个像素分为三块,每一块为一个字节,因此step[0] = 2250 ,step[1] = 3
    size表示的是每一维元素的大小,注意这里是元素,即像素,size[0]表示rows,size[1]表示cols
    elemSize表示的是每个元素的大小,以字节计,一个元素分为三块,一块是1字节,因此为3(彩色图像)
    elemSize1表示的是一个元素的每个通道的大小,因此为1

    http://lib.csdn.net/article/opencv/33141
    看完这篇文章,终于解决了我很多困惑,加强对Mat的结构的理解。同是有巩固了类的概念。
    Mat是一个类,它由两个数据部分组成:矩阵头和一个指向存储所有像素值的矩阵的指针。其中矩阵头包含了矩阵的尺寸、存储方法、储存地址等信息,由此可以看出矩阵头所占的内存很小,而具体储存所有像素值的矩阵则非常大。举个例子,比如一个班级,矩阵头就相当于储存了班级里有多少人、男女比多少、平均身高、平均体重等信息,而矩阵就储存了班级中所有同学的所有基本信息,每一个同学就相当于是一个像素点,而每个像素点的颜色信息、深度信息等一串数据就相当于是每个同学的身高、体重、性别等一系列信息组成的一串数据

    展开全文
  • opencv视频跟踪2

    2015-09-19 19:40:00
    在前面的报告中我们实现了用SURF算法计算目标在移动摄像机拍摄到的视频中的位置。由于摄像机本身像素的限制,加之算法处理时间会随着图像质量的提高而提高,实际实验发现...可行方案:用形态学找出目标的大致区域,...

    在前面的报告中我们实现了用SURF算法计算目标在移动摄像机拍摄到的视频中的位置。由于摄像机本身像素的限制,加之算法处理时间会随着图像质量的提高而提高,实际实验发现在背景复杂的情况下,结果偏差可能会很大。

    本次改进是预备在原先检测到的特征点上加上某种限制条件,以提高准确率。

    问题:如何判定检测到的特征点是否是我们需要的点(也就是目标区域上的点)?

    可行方案:用形态学找出目标的大致区域,然后对特征点判定。

    特征点(SURF算法或者其他的算法)已有,我们来一步步实现找到目标大致区域。

    下图假设为视频中的某一帧

    DSC_0185[1]

    我们要在这一帧中找出“停”字的大致区域(“停”的颜色和背景颜色可以酌情设置,并且和少量代码相关,可以修改)。

    目标被设置成了两种颜色(后面的操作也是基于两个通道R和B),原因是一种颜色太简单以致不好分离通道然后计算,三种颜色往上也没有必要,因为我们只计算两通道,多了会增加计算时间。(其他情况留作进一步的讨论)

    1、分离通道

    Mat img_scene = imread("image1.jpg");              //读取图像
    resize(img_scene,img_scene,cvSize(0,0),0.2,0.2);  //把图像调整到合适的大小
    vector<Mat> channels;
    split(img_scene, channels);     // 分离色彩通道, 把一个3通道图像转换成3个单通道图像  
    Mat img_scene_BlueChannel = channels.at(0);   // 红通道
    Mat img_scene_GreenChannel = channels.at(1);  // 绿通道
    Mat img_scene_RedChannel = channels.at(2);    // 蓝通道

    结果如下图:

    红色通道

    img_scene_RedChannel

    蓝色通道

    img_scene_BlueChannel

    我们看到原图的红色部分在red channel中位深色,蓝色部分在blue channel中为深色,这一步我们分离了目标的两个部分,两幅图得背景看起来差别不大。

    2、对图像进行二值化

    首先定义阈值

    #define threshold_value_red 150  // 红色通道阈值
    #define threshold_value_blue 160 // 蓝色通道阈值

    二值化处理

    Mat Seg_img_red;   // 红色通道阈值分割结果图
    Mat Seg_img_blue;  // 蓝色通道阈值分割结果图
    
    threshold(img_scene_RedChannel, Seg_img_red, threshold_value_red, 255, THRESH_BINARY);         // 红色通道进行阈值分割(大于阈值时候取255)
    threshold(img_scene_BlueChannel, Seg_img_blue, threshold_value_blue, 255, THRESH_BINARY);  // 蓝色通道进行阈值分割(小于阈值时候取255)
    
    imshow("Seg_img_red",Seg_img_red);
    imshow("Seg_img_blue",Seg_img_blue);

    处理结果

    Seg_img_blue

    Seg_img_red

    二值化后图像简单化了,去除了冗余,值得高兴的是目标看起来更突出了,目标区域似乎能够检测出来,但是背景也有大片干扰,下面就是用两个通道的好处了。

    3、合并图像

    这里我们注意到red channel中“停”字为黑色,背景是白色,而blue channel中刚好相反,于是想到试着对两幅图进行异或运算

    Mat Object_img;
    bitwise_xor(Seg_img_red, Seg_img_blue, Object_img);   // 求两个图像的交集获取目标的潜在颜色区域
    imshow("Object_img",Object_img);

    结果

    Object_img

    好的,看起来更好了,虽然背景还是有干扰(这也是无法避免的),目前我们已经使用上了两个通道的信息,只能继续往下寻找其他方法。

    4、腐蚀图像

    图像中有不少像胡椒粉一样的噪声,先用腐蚀去掉

    erode(Object_img,Object_img,cv::Mat());
    imshow("Object_img_erode",Object_img);

    结果

    Object_img_erode

    清爽不少

    5、计算连通域

    vector<vector<Point> > contours;
    findContours(Object_img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    Mat result(Object_img.size(), CV_8U, Scalar(0));
    drawContours(result, contours,      //画出轮廓
        -1, // 画出所有的轮廓
        Scalar(255), // 用白线画出
        2); // 轮廓线的粗细为2
    
    namedWindow("Contours");
    imshow("Contours", result);  // 显示图像中所有的连通域轮廓

    处理结果

    Contours

    有很多小的连通域,可以放心的先去掉

    6、连通域去噪

    方法一:

    // 去除图像中的连通域噪声
    int cmin = 50;  // 最小的轮廓长度
    int cmax = 1500; // 最大的轮廓长度
    vector<vector<Point>>::const_iterator itc = contours.begin();
    while (itc != contours.end()) 
    {
        if (itc->size() < cmin || itc->size() > cmax)
            itc = contours.erase(itc);   // 删除当前连通域轮廓
        else
            ++itc;
    }
    
    // 画出去掉连通域噪声后的连通域
    Mat original(Object_img.size(), CV_8U, Scalar(0));
    Mat result_hull(Object_img.size(), CV_8U, Scalar(0));
    Mat threshold_output(Object_img.size(), CV_8U, Scalar(0));
    drawContours(original, contours,
        -1, // 画出所有的轮廓
        Scalar(255), // 用白线画出
        1); // 轮廓线的粗度为2
    namedWindow("Contours noise reduced");
    imshow("Contours noise reduce", original);  // 画出去掉连通域噪声后的连通域

    处理结果(轮廓长度参数表示我们要选取适当的连通域,将范围缩小可以在单张图片中取得更好的结果,例如将cmin=400直接就有

    Contours on Animals

    但是为了在视频中处理要将范围适当放宽),结果如下:

    Contours on Animals

    看起来离目标不远了。

    方法二:

    方法一使用了人为设置的参数,但在视频处理中要尽量避免这种做法,方法二将得到的连通域按边界像素数量进行排序,然后选取边界像素数量最大的contours.size()*1/n数量的连通域(n按实际帧大小和摄像机距离目标距离等因素选取适当的值)。

    int *ca = new int[contours.size()];     //定义连通域边界像素排序数组
    itContours = contours.begin();
    for (int i = 0;i < contours.size(), itContours != contours.end();++i, ++itContours) 
    {
            
        ca[i] = itContours->size();
    }
    sort(ca, ca + contours.size());                 //按连通域边界像素的多少排序
    int s = contours.size()/10;
    int threshhold_con = ca[contours.size() - s];
    vector<vector<Point>>::const_iterator itc = contours.begin();
    while (itc != contours.end()) 
    {
        if (itc->size() < threshhold_con)
            itc = contours.erase(itc);   // 删除当前连通域轮廓
        else
            ++itc;
    }

    方法二结果

    Contours noise reduced

    看起来似乎没什么差别,算法复杂了一点,但为了最后在视频中处理,我们选用了第二种方法。

    7、计算连通域的凸包络、填充包络

    Mat result_hull(Object_img.size(), CV_8U, Scalar(0));
    Mat threshold_output(Object_img.size(), CV_8U, Scalar(0));
    /// 对每个轮廓计算其凸包
    vector<vector<Point> >hull( contours.size() );
    for( int i = 0; i < contours.size(); i++ )
           {      convexHull( Mat(contours[i]), hull[i], false ); }
    
    /// 绘出轮廓及其凸包
    Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
    for( int i = 0; i< contours.size(); i++ )
           {
                 Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
                 drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
                 drawContours( drawing, hull, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
         fillConvexPoly(result_hull,&hull[i][0],hull[i].size(),Scalar(255,0,0));
           }

    处理结果

    Hull demo

     

    result_hull

    实际上到这里,如果我们的把落入上图白色区域的特征点认为是正确的点已经能够减少一部分误差了,但本着精益求精的精神,还是应该再好一点。

     

    8、计算连通域的外接矩形

    这一步为可选项,可以看到前面一张图中的目标是近似正方形的,实际我们所用的目标就是正方形的,那么在摄像机离目标中心法线偏离角度不是太离谱的情况,得到的目标图像的外接矩形的长宽比的变化可以表示为一个固定的范围,这里思路是,计算所有连通域外接矩形长宽比(用短的比长的),得到一组0~1的浮点数,排序后和第七步一样选取适当的百分比,筛选长宽比靠近1的外接矩形和对应的连通域,代码如下:

    Rect *r = new Rect[contours.size()];//定义外接矩形数组
    double *ra = new double[contours.size()];     //定义外接矩形长宽比数组
    double *rb = new double[contours.size()];
    Mat obj_rec = Mat::zeros( threshold_output.size(), CV_8UC3 );
    for( int i = 0; i < contours.size(); i++ )
        {  
            convexHull( Mat(contours[i]), hull[i], false );
            r[i] = boundingRect(Mat(contours[i]));//boundingRect获取这个外接矩形;
            rb[i] = ra[i] = rate(r[i].width,r[i].height);    //计算长宽比
            rectangle(obj_rec, r[i], Scalar(255), 2);
        }
    sort(ra,ra+contours.size());        //将外接矩形长宽比排序
    int k = contours.size()/3;                            
    double threshhold_rate = ra[contours.size() - k];    //定义外接矩形长宽比阈值
    //绘制通过长宽比阈值限制后的外接矩形
    Mat obj_rec_thr = Mat::zeros( threshold_output.size(), CV_8UC3 );
    itContours = contours.begin();
    for( int i = 0; i < contours.size(), itContours != contours.end(); ++i)
    {
        if(rb[i]>threshhold_rate)
        {
            rectangle(obj_rec_thr, r[i], Scalar(255,0,0), 2);
            ++itContours;
        }
        else
            itContours = contours.erase(itContours);
    }

    筛选前外接矩形:

    obj_rec

    筛选后连通域外接矩形:

    obj_rec_thr

    相应的连通域图:

    Hull demo

    只剩下一点噪声了。

     

    9、去掉最后的噪声

    第三步中合并图像我们使用的是异或(xor),也就是同一个位置像素在两个通道中值相同和不同这两种结果在目标图像中以黑和白区分开来了,我们这个例子中目标图像白色区域是为两个通道相同像素点值不同的结果。也就是说,前一张图中的两块连通域中的像素在第二步阈值处理后的两张图中相应位置的像素值刚好不同。于是我们将得到的两个连通域的外接矩形设置为兴趣区,我们得到两个兴趣区,以第一个兴趣区的位置和大小在阈值处理后的图像上分别截取对应的区域(做这步我们要将

    threshold(img_scene_RedChannel, Seg_img_red, threshold_value_red, 255, THRESH_BINARY);         // 红色通道进行阈值分割(大于阈值时候取255)
    threshold(img_scene_BlueChannel, Seg_img_blue, threshold_value_blue, 255, THRESH_BINARY);  // 蓝色通道进行阈值分割(小于阈值时候取255)

    中的255改为1,方便累加处理),又得到两块区域,分别求像素和sum_red,sum_blue,求比值(小的比大的),我们得目标区域是既有蓝色的又有红色的(比值可通过自己设计目标图形和颜色修改),噪声区域是不一定的,我们只保留比值大于0.2的,太小的就不要了。

    实现代码

    for( int i = 0; i < contours.size(), itContours != contours.end(); ++i)
        {
            if(rb[i]>threshhold_rate)
            {
                rectangle(obj_rec_thr, r[i], Scalar(255,0,0), 2);
    //            ++itContours;
                Mat imageROI_red = Seg_img_red(cv::Rect(r[i].x, r[i].y, r[i].width, r[i].height));
                Mat imageROI_blue = Seg_img_blue(cv::Rect(r[i].x, r[i].y, r[i].width, r[i].height));
    
                long long int sum_red = 0, sum_blue = 0;
                int nr=imageROI_red.rows;
                 int nc=imageROI_red.cols;
    //             outImage.create(image.size(),image.type());
                 if(imageROI_red.isContinuous())
                 {
                     nr=1;
                     nc=nc*imageROI_red.rows*imageROI_red.channels();
                 }
                 for(int i=0;i<nr;i++)
                 {
                     const uchar* Data_red=imageROI_red.ptr<uchar>(i);
                     const uchar* Data_blue=imageROI_blue.ptr<uchar>(i);
    //                 uchar* outData=outImage.ptr<uchar>(i);
                     for(int j=0;j<nc;j++)
                     {
                         sum_red += *Data_red;
                         sum_blue += *Data_blue;
    //                     *outData++=*inData++/div*div+div/2;
                     }
                 }
                  double pixel_sum_rate = rate((double)sum_red, (double)sum_blue);
                 cout << sum_red << "," << sum_blue << endl;
                 cout << pixel_sum_rate << endl;
    
    
                 if(pixel_sum_rate < 0.2)
                     itContours = contours.erase(itContours);
                 else
                     ++itContours;
    
                imshow("imageROI_red", imageROI_red);
                imshow("imageROI_blue", imageROI_blue);
            }
            else
                itContours = contours.erase(itContours);
        }

    代码是直接在第八步中插入的,结果如下:

    Hull demo

    通过输出中间值可看到

    image

    第一个外接矩形区域sum_red=0,sum_blue=420,比值为0;

    第二个外接矩形区域sum_red=12317,sum_blue=9153,比值为0.743119;

    10、结论

    我们已经成功找到目标所在区域,实现了预期的效果,用这个区域去限制SURF特征点预计可以得到更加精确的结果。

    转载于:https://www.cnblogs.com/programnote/p/4822076.html

    展开全文
  • 11.04.10 ~ 11.04.16

    2011-04-15 21:52:00
    8:45 2011-4-10 报告用PPT。大体做完,措辞需要调整。 8:12 2011-4-11 ~ 9:03 2011-4-11 ...形态学方法的结构元素内容。 可变长度的结构元素。 16:03 2011-4-11 ~ 18:00 2011-4-11 讨论
  • 收集精液后,根据世界卫生组织的建议,由受过训练的胚胎家在男科学实验室中手动进行常规精液分析。 对结果进行统计分析,并提供平均值。 结果:精液分析后,我们报告平均精液量为3.29 ml,精子浓度为40.68×106 /...
  • 数据结构(C++)有关练习题

    热门讨论 2008-01-02 11:27:18
    实验报告要求: 按要求写出完整的实验代码; <br>实验二 单链表结构及计算 实验目的: 通过实验掌握下列知识: 1、熟悉线性表的基本运算在两种存储结构(顺序结构和链式结构)上的实现; 2、...
  • 二叉排序树与平衡二叉树的实现

    热门讨论 2010-12-26 15:25:31
    35% 04 综合运用知识的能力 10 能运用所知识和技能去发现与解决实际问题,能正确处理实验数据,能对课题进行理论分析,得出有价值的结论。 05 应用文献的能力 5 能独立查阅相关文献和从事其他调研;能提出并较...

空空如也

空空如也

1
收藏数 20
精华内容 8
关键字:

形态学实验报告