如何正确平滑图像的色调?

时间:2016-04-23 12:28:59

标签: algorithm image-processing

假设您在某种色彩空间中有一个带有色调状通道的图像,即一个固有圆形的通道。
例如,在典型的HSL或HSV通道中,0或25的色调都对应于完全相同的颜色,通常是纯红色,而255则略微偏蓝,但仍然几乎是纯红色。 现在,如果您在这样的通道上应用高斯模糊,沿着0和255触摸的线,您可以将其平滑并且#34;漫长的路程,在穿过整个彩虹的两个红色之间形成一个渐变。 - 几乎肯定不会想到这个结果。

由于亮度/值和/或饱和度为0的奇点而发生第二个问题,在这种情况下,Hue在技术上可以采用任意值。 - 大多数色彩空间转换只是在转换色彩空间时选择0的色调,因为对于几乎所有常见的用例来说,它都不重要。但如果我要模糊,那绝对是。

如何更改典型的高斯模糊算法以至少妥善处理(更重要的)第一个问题,理想情况下也是第二个问题?

我认为第二个更难以完成,仅仅使用Hue通道无法完成,但是宁愿需要来自其他两个的信息来处理奇点的特殊情况,但希望有一些相当简单的调整可以修复第一个

如果答案需要特定的算法,一个简单快捷的方法就是使用重复的盒子卷积进行近似,例如here

为方便起见,这里是来自该网站的复制+粘贴,执行三个水平和三个垂直框卷积:

function gaussBlur_4 (scl, tcl, w, h, r) {
    var bxs = boxesForGauss(r, 3);
    boxBlur_4 (scl, tcl, w, h, (bxs[0]-1)/2);
    boxBlur_4 (tcl, scl, w, h, (bxs[1]-1)/2);
    boxBlur_4 (scl, tcl, w, h, (bxs[2]-1)/2);
}
function boxBlur_4 (scl, tcl, w, h, r) {
    for(var i=0; i<scl.length; i++) tcl[i] = scl[i];
    boxBlurH_4(tcl, scl, w, h, r);
    boxBlurT_4(scl, tcl, w, h, r);
}
function boxBlurH_4 (scl, tcl, w, h, r) {
    var iarr = 1 / (r+r+1);
    for(var i=0; i<h; i++) {
        var ti = i*w, li = ti, ri = ti+r;
        var fv = scl[ti], lv = scl[ti+w-1], val = (r+1)*fv;
        for(var j=0; j<r; j++) val += scl[ti+j];
        for(var j=0  ; j<=r ; j++) { val += scl[ri++] - fv       ;   tcl[ti++] = Math.round(val*iarr); }
        for(var j=r+1; j<w-r; j++) { val += scl[ri++] - scl[li++];   tcl[ti++] = Math.round(val*iarr); }
        for(var j=w-r; j<w  ; j++) { val += lv        - scl[li++];   tcl[ti++] = Math.round(val*iarr); }
    }
}
function boxBlurT_4 (scl, tcl, w, h, r) {
    var iarr = 1 / (r+r+1);
    for(var i=0; i<w; i++) {
        var ti = i, li = ti, ri = ti+r*w;
        var fv = scl[ti], lv = scl[ti+w*(h-1)], val = (r+1)*fv;
        for(var j=0; j<r; j++) val += scl[ti+j*w];
        for(var j=0  ; j<=r ; j++) { val += scl[ri] - fv     ;  tcl[ti] = Math.round(val*iarr);  ri+=w; ti+=w; }
        for(var j=r+1; j<h-r; j++) { val += scl[ri] - scl[li];  tcl[ti] = Math.round(val*iarr);  li+=w; ri+=w; ti+=w; }
        for(var j=h-r; j<h  ; j++) { val += lv      - scl[li];  tcl[ti] = Math.round(val*iarr);  li+=w; ti+=w; }
    }
}

function boxesForGauss(sigma, n)  // standard deviation, number of boxes
{
    var wIdeal = Math.sqrt((12*sigma*sigma/n)+1);  // Ideal averaging filter width 
    var wl = Math.floor(wIdeal);  if(wl%2==0) wl--;
    var wu = wl+2;

    var mIdeal = (12*sigma*sigma - n*wl*wl - 4*n*wl - 3*n)/(-4*wl - 4);
    var m = Math.round(mIdeal);
    // var sigmaActual = Math.sqrt( (m*wl*wl + (n-m)*wu*wu - n)/12 );

    var sizes = [];  for(var i=0; i<n; i++) sizes.push(i<m?wl:wu);
    return sizes;
}

但我主要对实际的算法更改感兴趣,而不一定是特定语言的特定实现。

1 个答案:

答案 0 :(得分:2)

保留在Hue颜色空间中,并使用循环数据统计信息,请参阅herehere

高斯滤波器只是一个卷积滤波器,所以基本上是一个加权平均值。所以在这样的颜色空间中,你只需使用加权循环平均值:它是通过将每个值/角度分解为sin / cos,然后平均sin / cos,然后返回角度/值来计算的。