如何从给定的样本图像中提取色调,以使用样本图像的颜色转换另一个图像?

时间:2015-05-17 06:44:49

标签: image image-processing colors rgb

我有一个示例图像和一个目标图像。我想将样本图像的色调转移到目标图像。请告诉我如何从样本图像中提取颜色。

这里是图片:

输入源图片:

enter image description here

所需输出图像的输入地图

enter image description here

输出图片

enter image description here

5 个答案:

答案 0 :(得分:1)

您可以使用名为" Histogram matching" (another description

基本上,您使用源图像的直方图作为目标,并转换每个输入地图像素的值,以使输出直方图尽可能接近源。您可以为图像的每个rgb通道执行此操作。

这是我的python代码:

from scipy.misc import imsave, imread
import numpy as np

imsrc = imread("source.jpg")
imtint = imread("tint_target.jpg")
nbr_bins=255
imres = imsrc.copy()
for d in range(3):
    imhist,bins = np.histogram(imsrc[:,:,d].flatten(),nbr_bins,normed=True)
    tinthist,bins = np.histogram(imtint[:,:,d].flatten(),nbr_bins,normed=True)

    cdfsrc = imhist.cumsum() #cumulative distribution function
    cdfsrc = (255 * cdfsrc / cdfsrc[-1]).astype(np.uint8) #normalize

    cdftint = tinthist.cumsum() #cumulative distribution function
    cdftint = (255 * cdftint / cdftint[-1]).astype(np.uint8) #normalize


    im2 = np.interp(imsrc[:,:,d].flatten(),bins[:-1],cdfsrc)


    im3 = np.interp(imsrc[:,:,d].flatten(),cdftint, bins[:-1])

    imres[:,:,d] = im3.reshape((imsrc.shape[0],imsrc.shape[1] ))

imsave("histnormresult.jpg", imres)

您的样本输出将如下所示:

enter image description here

您也可以尝试在HSV色彩空间中进行相同的操作 - 它可能会产生更好的效果。

答案 1 :(得分:1)

  1. 从彩色地图中获取平均颜色

    忽略饱和的白/黑色

  2. 将光照地图转换为灰度

  3. 更改光照贴图的动态范围以匹配您想要的输出

    我使用最大动态范围。您可以计算颜色贴图的范围并将其设置为光照贴图

  4. 以平均颜色乘以光照地图

  5. 这就是它的样子:

    • recolor example

    这是C ++源代码

    //picture pic0,pic1,pic2;
        // pic0 - source color
        // pic1 - source light map
        // pic2 - output
    int x,y,rr,gg,bb,i,i0,i1;
    double r,g,b,a;
    
    // init output as source light map in grayscale i=r+g+b
    pic2=pic1;
    pic2.rgb2i();
    // change light map dynamic range to maximum
    i0=pic2.p[0][0].dd; // min
    i1=pic2.p[0][0].dd; // max
    for (y=0;y<pic2.ys;y++)
     for (x=0;x<pic2.xs;x++)
        {
        i=pic2.p[y][x].dd;
        if (i0>i) i0=i;
        if (i1<i) i1=i;
        }
    for (y=0;y<pic2.ys;y++)
     for (x=0;x<pic2.xs;x++)
        {
        i=pic2.p[y][x].dd;
        i=(i-i0)*767/(i1-i0);
        pic2.p[y][x].dd=i;
        }
    // extract average color from color map (normalized to unit vecotr)
    for (r=0.0,g=0.0,b=0.0,y=0;y<pic0.ys;y++)
     for (x=0;x<pic0.xs;x++)
        {
        rr=BYTE(pic0.p[y][x].db[picture::_r]);
        gg=BYTE(pic0.p[y][x].db[picture::_g]);
        bb=BYTE(pic0.p[y][x].db[picture::_b]);
        i=rr+gg+bb;
        if (i<400) // ignore saturated colors (whiteish) 3*255=white
         if (i>16) // ignore too dark colors (whiteish) 0=black
            {
            r+=rr;
            g+=gg;
            b+=bb;
            }
        }
    a=1.0/sqrt((r*r)+(g*g)+(b*b)); r*=a; g*=a; b*=a;
    // recolor output
    for (y=0;y<pic2.ys;y++)
     for (x=0;x<pic2.xs;x++)
        {
        a=DWORD(pic2.p[y][x].dd);
        rr=r*a; if (rr>255) rr=255; pic2.p[y][x].db[picture::_r]=BYTE(rr);
        gg=g*a; if (gg>255) gg=255; pic2.p[y][x].db[picture::_g]=BYTE(gg);
        bb=b*a; if (bb>255) bb=255; pic2.p[y][x].db[picture::_b]=BYTE(bb);
        }
    

    我正在使用自己的图片类,所以这里有一些成员:


    xs,ys图片大小(以像素为单位)  
    p[y][x].dd是(x,y)位置的像素,为32位整数类型  
    p[y][x].db[4]是色带(r,g,b,a)的像素访问

    <强> [注释]

    如果这不符合您的需求,请指定更多并添加更多图片。因为你当前的例子真的不是自我解释的

答案 2 :(得分:1)

我认为最难的部分是确定第一张图像的主色。只需观察它,所有的高光和阴影,最好的整体颜色将是具有最高亮度和饱和度组合的颜色。我从一个模糊的图像开始,以减少噪声和其他异常的影响,然后将每个像素转换为HSV颜色空间进行亮度和饱和度测量。以下是使用PILcolorsys在Python中查看的内容:

blurred = im1.filter(ImageFilter.BLUR)
ld = blurred.load()
max_hsv = (0, 0, 0)
for y in range(blurred.size[1]):
    for x in range(blurred.size[0]):
        r, g, b = tuple(c / 255. for c in ld[x, y])
        h, s, v = colorsys.rgb_to_hsv(r, g, b)
        if s + v > max_hsv[1] + max_hsv[2]:
            max_hsv = h, s, v
r, g, b = tuple(int(c * 255) for c in colorsys.hsv_to_rgb(*max_hsv))

对于你的图像,我得到的颜色为(210,61,74),如下所示:

(210, 61, 74)

从那时起,只需将色调和饱和度转移到另一个图像。

答案 3 :(得分:1)

以上直方图匹配解决方案不适用于我。这是我自己的,基于OpenCV:

def match_image_histograms(image, reference):
    chans1 = cv2.split(image)
    chans2 = cv2.split(reference)

    new_chans = []
    for ch1, ch2 in zip(chans1, chans2):
        hist1 = cv2.calcHist([ch1], [0], None, [256], [0, 256])
        hist1 /= hist1.sum()
        hist2 = cv2.calcHist([ch2], [0], None, [256], [0, 256])
        hist2 /= hist2.sum()
        lut = np.searchsorted(hist1.cumsum(), hist2.cumsum())
        new_chans.append(cv2.LUT(ch1, lut))
    return cv2.merge(new_chans).astype('uint8')

答案 4 :(得分:0)

关于以前的回答,有一点需要注意: 一旦CDF达到其最大值(= 1),插值将被误导并且将错误地匹配您的值。为了避免这种情况,你应该只提供插值函数,只有CDF的一部分有意义(不是在达到1之后)和相应的二进制数。这里答案适应:

from scipy.misc import imsave, imread
import numpy as np

imsrc = imread("source.jpg")
imtint = imread("tint_target.jpg")
nbr_bins=255
imres = imsrc.copy()
    for d in range(3):
    imhist,bins = np.histogram(imsrc[:,:,d].flatten(),nbr_bins,normed=True)
    tinthist,bins = np.histogram(imtint[:,:,d].flatten(),nbr_bins,normed=True)

    cdfsrc = imhist.cumsum() #cumulative distribution function
    cdfsrc = (255 * cdfsrc / cdfsrc[-1]).astype(np.uint8) #normalize

    cdftint = tinthist.cumsum() #cumulative distribution function
    cdftint = (255 * cdftint / cdftint[-1]).astype(np.uint8) #normalize


    im2 = np.interp(imsrc[:,:,d].flatten(),bins[:-1],cdfsrc)

    if (cdftint==1).sum()>0:
            idx_max = np.where(cdftint==1)[0][0]
            im3 = np.interp(im2,cdftint[:idx_max+1], bins[:idx_max+1])
    else:
            im3 = np.interp(im2,cdftint, bins[:-1])

享受!