【问题标题】:How to properly smooth the hue of an image?如何正确平滑图像的色调?
【发布时间】:2016-04-24 02:00:10
【问题描述】:

假设您在某种颜色空间中有一个图像,该图像具有类似色调的通道,即本质上是圆形的通道。
例如,在典型的 HSL 或 HSV 通道中,色调 0 或色调 256 都对应于完全相同的颜色,通常是纯红色,而 255 则稍微偏蓝一些,但仍然几乎是纯红色。
现在,如果你在这样的通道上应用高斯模糊,沿着 0 和 255 接触的线,你会“平滑”很长一段路,在穿过整个彩虹的两个红色之间形成渐变。 - 这个结果几乎肯定不是我们想要的。

第二个问题是由于亮度/值和/或饱和度为 0 处的奇点而发生的,在这种情况下,色调在技术上可以采用任意值。 - 大多数颜色空间转换只是在转换颜色空间时选择 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;
}

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

【问题讨论】:

  • 我认为没有人会理解你的第二段

标签: algorithm image-processing


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-15
    • 2011-02-19
    • 2014-11-18
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    相关资源
    最近更新 更多