今天介绍 Siggraph 2004 年的一篇文章: Colorization using Optimization,利用优化的方法对灰度图像进行着色,这里用到了非常经典的泊松方程以及稀疏矩阵的线性优化。简单来说,就是对一张灰度图像先人为地进行着色,然后利用优化的方法,对其他的没有颜色的区域进行填充。这些处理都是在 YUV 颜色空间进行的。

给定一个 Y 通道的图像,我们希望基于一定的先验知识,恢复出图像的U, V 通道。这里的一个重要假设就是 对于相邻的两个像素,如果其亮度比较相似,那么其颜色也应该相似。

假设 rs 表示相邻两个像素的位置,那么我们希望最小化如下的目标函数:

J(U)=rU(r)sN(r)wrsU(s)2

对于 V 通道,我们可以建立类似的目标函数,而其中的系数 wrs 可以由 Y 通道表示:

wrs=e(Y(r)Y(s))2/2σ2

只要给定了 σ 以及像素的位置关系,我们可以很方便的求出系数 wrs

首先,需要对图像进行一些简单的着色,我们可以得到一系列的像素点 ri 的颜色值, u(ri)=ui, v(ri)=vi , 根据这些预先设定的像素点的颜色值,再结合上面的目标函数,我们可以建立一个很大的稀疏线性方程组,假设图像的尺寸为 M×N, 那么图像的像素个数为 np=MN, 我们要解的方程组将是 np 个,稀疏矩阵的大小为 np×np,比如一张 800×600 的图像,需要解的方程组将是 480000 个,稀疏矩阵的大小将是 480000×480000 这是一个非常大的矩阵。不过由于这是稀疏的,所以会有很多标准的解法。

下面给出 matlab 代码


g_name='example.bmp';
c_name='example_marked.bmp';
out_name='example_res.bmp';

%set solver=1 to use a multi-grid solver 
%and solver=2 to use an exact matlab "\" solver
solver=2; 

gI=double(imread(g_name))/255;
cI=double(imread(c_name))/255;
colorIm=(sum(abs(gI-cI),3)>0.01);
colorIm=double(colorIm);

sgI=rgb2ntsc(gI);
scI=rgb2ntsc(cI);

ntscIm(:,:,1)=sgI(:,:,1);
ntscIm(:,:,2)=scI(:,:,2);
ntscIm(:,:,3)=scI(:,:,3);


max_d=floor(log(min(size(ntscIm,1),size(ntscIm,2)))/log(2)-2);
iu=floor(size(ntscIm,1)/(2^(max_d-1)))*(2^(max_d-1));
ju=floor(size(ntscIm,2)/(2^(max_d-1)))*(2^(max_d-1));
id=1; jd=1;
colorIm=colorIm(id:iu,jd:ju,:);
ntscIm=ntscIm(id:iu,jd:ju,:);

if (solver==1)
  nI=getVolColor(colorIm,ntscIm,[],[],[],[],5,1);
  nI=ntsc2rgb(nI);
else
  nI=getColorExact(colorIm,ntscIm);
end

figure, imshow(nI)

imwrite(nI,out_name)


function [nI,snI]=getColorExact(colorIm,ntscIm)

n=size(ntscIm,1); m=size(ntscIm,2);
imgSize=n*m;


nI(:,:,1)=ntscIm(:,:,1);

indsM=reshape([1:imgSize],n,m);
lblInds=find(colorIm);

wd=1; 

len=0;
consts_len=0;
col_inds=zeros(imgSize*(2*wd+1)^2,1);
row_inds=zeros(imgSize*(2*wd+1)^2,1);
vals=zeros(imgSize*(2*wd+1)^2,1);
gvals=zeros(1,(2*wd+1)^2);


for j=1:m
   for i=1:n
      consts_len=consts_len+1;

      if (~colorIm(i,j))   
        tlen=0;
        for ii=max(1,i-wd):min(i+wd,n)
           for jj=max(1,j-wd):min(j+wd,m)

              if (ii~=i)|(jj~=j)
                 len=len+1; tlen=tlen+1;
                 row_inds(len)= consts_len;
                 col_inds(len)=indsM(ii,jj);
                 gvals(tlen)=ntscIm(ii,jj,1);
              end
           end
        end
        t_val=ntscIm(i,j,1);
        gvals(tlen+1)=t_val;
        c_var=mean((gvals(1:tlen+1)-mean(gvals(1:tlen+1))).^2);
        csig=c_var*0.6;
        mgv=min((gvals(1:tlen)-t_val).^2);
        if (csig<(-mgv/log(0.01)))
       csig=-mgv/log(0.01);
    end
    if (csig<0.000002)
       csig=0.000002;
        end

        gvals(1:tlen)=exp(-(gvals(1:tlen)-t_val).^2/csig);
        gvals(1:tlen)=gvals(1:tlen)/sum(gvals(1:tlen));
        vals(len-tlen+1:len)=-gvals(1:tlen);
      end


      len=len+1;
      row_inds(len)= consts_len;
      col_inds(len)=indsM(i,j);
      vals(len)=1; 

   end
end


vals=vals(1:len);
col_inds=col_inds(1:len);
row_inds=row_inds(1:len);


A=sparse(row_inds,col_inds,vals,consts_len,imgSize);
b=zeros(size(A,1),1);


for t=2:3
    curIm=ntscIm(:,:,t);
    b(lblInds)=curIm(lblInds);
    new_vals=A\b;   
    nI(:,:,t)=reshape(new_vals,n,m,1);    
end

snI=nI;
nI=ntsc2rgb(nI);

posted on 2017-11-01 20:40  未雨愁眸  阅读(724)  评论(0编辑  收藏  举报