水下图像增强相关算法的一个简单小结。

最近一直没有找到感兴趣的研究课题,下了几个最新的去雾的论文,随便看了下,觉得都是为了写论文而做的论文,没有什么创新性,也就没有想法去实现他们。偶尔看到了一些关于水下图像增强方面的文章,闲来无聊试着去看看效果,不过也觉得非常让人失望,似乎并没有特别有效的算法。

      就我看得几篇文章而言,这类算法都不是从原理上、或者说某一个数学模型、抑或是某种先验知识出发,而提出的算法,都是一种没有什么特强的理论支持,只是通过一些实际的试验而得到的一些过程而已。这些过程对于论文本身中提供的测试图像都有着较为理想的处理效果,而一旦选择一副其他性质的水下图像,其结果往往难以令人满意。因此,也就没有类似于去雾算法界暗通道先验那样不可逾越的黄金文章了。

       我看了三篇文章,第一篇是Underwater Image Enhancement Using an Integrated Colour Model,07年的文章,算法的细路很简单,借用文章中的一副流程图来说明下:

     很简单的步骤,首先是进行对比度拉升,可以看成是类似于PS中的自动对比度,接着将处理后的图像转换到HSI颜色空间,在对S和I分量进行拉升,之后再将HSI空间的数据转换到RGB空间得到最终的图像。在百度上搜索谁下图像增强,能搜索到一个相关的专利,见http://www.google.com/patents/CN102930512A?cl=zh,这个专利的内容其实也没啥新意,一样的就是在HSI空间将S和I分量用其他的方式进行了拉升和处理,还是发明专利,呵呵,大家都知道国内专利是怎么回事。

      这篇论文对算法部分的描述还是过于简单,虽然对比度拉升给了个公式,但并没有明确的说明S和I分量的具体处理流程,他给的两篇参考文献对应的网站也无法打开了,因此无法对原始的算法进行验证,我用GIMP的对比度拉升 + HSV拉升未能达到论文中的效果。 

       第二篇和第三篇都是用的图像融合的方式来处理的,分别是Enhancing Underwater Images and Videos by Fusion以及Effective Single Underwater Image Enhancement by Fusion,后一篇是国内合工大和中科大的作者写的,很明显可以看得出模仿的笔迹 。

       其实这种通过融合的方式也很简单,就是先找两种算法得到对原图两种不同程度的增强的结果,然后选择好一个融合系数的计算公式,再进行拉普拉斯金字塔融合,从而提取更好的结果。Enhancing Underwater Images and Videos by Fusion这篇文章就是选用了白平衡的结果(记为I1)作为融合的对象一, 用对I1进行双边滤波+CALHE之类的算法处理的结果(记为I2)作为融合的对象2。标准的拉普拉斯融合的融合算法一般有:最大值、最小值、平均值,这里则修改为某一种权重系数的融合,最后进行拉普拉斯融合。

       因此,这个算法的处理结果的好坏性完全取决于融合的对象,即两个前处理算法。但是同样存在的问题就是算法的普遍适应性,某一种前处理对某一类合适,对其他的就不一定了。

       我这里经过一些实验,也提出一种前处理算法,这个算法的效果可以在GIMP的颜色--》自动--》色调均化中看到。

       虽然GIMP是一个类似PS的软件,但两者的色调均化效果完全不同,查看GIMP的代码就能知道这是为什么了,我这里贴出GIMP的这个算法的核心代码部分:

static void
equalize_lut_setup (GimpLut       *lut,
                    GimpHistogram *hist,
                    gint           n_channels)
{
  gint            i, k, j;
  hist_lut_struct hlut;
  gdouble         pixels_per_value;
  gdouble         desired;
  gdouble         sum, dif;

  g_return_if_fail (lut != NULL);
  g_return_if_fail (hist != NULL);

  /* Find partition points */
  pixels_per_value = gimp_histogram_get_count (hist,
                                               GIMP_HISTOGRAM_VALUE,
                                               0, 255) / 256.0;

  for (k = 0; k < n_channels; k++)
    {
      /* First and last points in partition */
      hlut.part[k][0]   = 0;
      hlut.part[k][256] = 256;

      /* Find intermediate points */
      j   = 0;
      sum = (gimp_histogram_get_channel (hist, k, 0) +
             gimp_histogram_get_channel (hist, k, 1));

      for (i = 1; i < 256; i++)
        {
          desired = i * pixels_per_value;

          while (sum < desired && j < 256)
            {
              j++;
              sum += gimp_histogram_get_channel (hist, k, j + 1);
            }

          /* Nearest sum */
          dif = sum - gimp_histogram_get_channel (hist, k, j);

          if ((sum - desired) > (dif / 2.0))
            hlut.part[k][i] = j;
          else
            hlut.part[k][i] = j + 1;
        }
    }

  gimp_lut_setup (lut, (GimpLutFunc) equalize_lut_func, &hlut, n_channels);
}
void
gimp_lut_setup (GimpLut     *lut,
                GimpLutFunc  func,
                void        *user_data,
                gint         nchannels)
{
  guint   i, v;
  gdouble val;

  if (lut->luts)
    {
      for (i = 0; i < lut->nchannels; i++)
        g_free (lut->luts[i]);

      g_free (lut->luts);
    }

  lut->nchannels = nchannels;
  lut->luts      = g_new (guchar *, lut->nchannels);

  for (i = 0; i < lut->nchannels; i++)
    {
      lut->luts[i] = g_new (guchar, 256);

      for (v = 0; v < 256; v++)
        {
          /* to add gamma correction use func(v ^ g) ^ 1/g instead. */
          val = 255.0 * func (user_data, lut->nchannels, i, v/255.0) + 0.5;

          lut->luts[i][v] = CLAMP (val, 0, 255);
        }
    }
}

  gimp的代码看起来相当晦涩的,但是实际上上述算法要描述的意思很简单,就是我希望我调整后的图像的直方图在每个色阶上的分布概率都是一样的。其实这个过程就可以看成是直方图规定化的一个过程,举例如下:

原  图

                                                                  处理后的图

         原图B/G/R对应的直方图|待匹配的直方图|处理后的直方图

 可见处理后的直方图已尽量向带匹配的模式靠近,但不可能完全一样。

     用这个过程处理了几幅论文中带的水下图像,效果如下:

    最后一幅图在Enhancing Underwater Images and Videos by Fusion一文中的效果是非常棒的,主要是过度的很自然,这个应该融合在其作用吧。

    融合这种处理方式确实一个值得推广的想法,因此那篇论文才会成为2012的CVPR论文之一的。

*********************************作者: laviewpbt   时间: 2014.4.6   联系QQ:  33184777  转载请保留本行信息************************

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

Spark踩坑——java.lang.AbstractMethodError

百度了一下说是版本不一致导致的。于是重新检查各个jar包,发现spark-sql-kafka的版本是2.2,而spark的版本是2.3,修改spark-sql-...

1260
来自专栏Java Edge

AbstractList源码解析1 实现的方法2 两种内部迭代器3 两种内部类3 SubList 源码分析4 RandomAccessSubList 源码:AbstractList 作为 Lis

它实现了 List 的一些位置相关操作(比如 get,set,add,remove),是第一个实现随机访问方法的集合类,但不支持添加和替换

622
来自专栏学海无涯

Android开发之奇怪的Fragment

说起Android中的Fragment,在使用的时候稍加注意,就会发现存在以下两种: v4包中的兼容Fragment,android.support.v4.ap...

3215
来自专栏ml

朴素贝叶斯分类器(离散型)算法实现(一)

1. 贝叶斯定理:        (1)   P(A^B) = P(A|B)P(B) = P(B|A)P(A)   由(1)得    P(A|B) = P(B|...

3597
来自专栏拭心的安卓进阶之路

Java 集合深入理解(12):古老的 Vector

今天刮台风,躲屋里看看 Vector ! 都说 Vector 是线程安全的 ArrayList,今天来根据源码看看是不是这么相...

2547
来自专栏xingoo, 一个梦想做发明家的程序员

20120918-向量实现《数据结构与算法分析》

#include <iostream> #include <list> #include <string> #include <vector> #include...

1856
来自专栏desperate633

LeetCode Invert Binary Tree题目分析

Invert a binary tree. 4 / \ 2 7 / \ / \1 3 6 9 to4 / \ 7 2 / \ / \9 6 3 1 Tri...

981
来自专栏开发与安全

算法:AOV网(Activity on Vextex Network)与拓扑排序

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称之为AOV网(Activity on Vextex ...

3987
来自专栏Hongten

ArrayList VS Vector(ArrayList和Vector的区别)_面试的时候经常出现

2232
来自专栏项勇

笔记68 | 切换fragmengt的replace和add方法笔记

1524

扫码关注云+社区