最近一直没有找到感兴趣的研究课题,下了几个最新的去雾的论文,随便看了下,觉得都是为了写论文而做的论文,没有什么创新性,也就没有想法去实现他们。偶尔看到了一些关于水下图像增强方面的文章,闲来无聊试着去看看效果,不过也觉得非常让人失望,似乎并没有特别有效的算法。
就我看得几篇文章而言,这类算法都不是从原理上、或者说某一个数学模型、抑或是某种先验知识出发,而提出的算法,都是一种没有什么特强的理论支持,只是通过一些实际的试验而得到的一些过程而已。这些过程对于论文本身中提供的测试图像都有着较为理想的处理效果,而一旦选择一副其他性质的水下图像,其结果往往难以令人满意。因此,也就没有类似于去雾算法界暗通道先验那样不可逾越的黄金文章了。
我看了三篇文章,第一篇是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论文之一的。