颜色匹配 Matlab版本

时间:2020-12-13 04:54:28

在直方图的基础之上,考虑均值方差匹配(本质上根据直方图完成一次线性映射,y=kx+b;),来达到颜色匹配的效果。(颜色匹配在PS软件上也有类似功能)

匹配分为两个阶段:第一阶段,在HSV空间下对S、V通道进行匹配,H通道不变。会有些许色片。(对于HSV空间的理解,此处不足解释,自己查阅资料看)

第二阶段,将HSV空间下做好的匹配图转换到RGB空间下,在对R、G、B三通道分别进行匹配。这样就完成了。

过程中(指导老师提供了思想),遇到问题冷静思考解决,一步步去测试(直方图、均值、方差、映射系数、映射矩阵。。。)

自己碰到的麻烦;变量名的误写,最终的映射代码逻辑写反了(这个逻辑读者一定要注意)。

以下只给出HSV空间下的匹配代码(RGB空间用到的匹配思想是一样的,读者自行学习编写):

clear all;
close all;
clc;
%注意点乘和乘的区别
src=imread('E:\毕设图片\颜色匹配\source.jpg');
tar=imread('E:\毕设图片\颜色匹配\target.jpg');
src=mat2gray(src);
tar=mat2gray(tar);%归一化
[m,n,dim]=size(src);
[m,n,dim]=size(tar);


%%读取待匹配图像,将其的RGB转换成HSV
src_R=src(:,:,1);
src_G=src(:,:,2);
src_B=src(:,:,3);
%RGB—>HSV
src_H=zeros(m,n);   %色相角
src_S=zeros(m,n);   %饱和度
src_V=zeros(m,n);   %明度
for i=1:m
   for j=1:n
       r=src_R(i,j);
       g=src_G(i,j);
       b=src_B(i,j);
       MAX=max([r,g,b]);
       MIN=min([r,g,b]);


       if MAX==MIN
            src_H(i,j)=0;
       elseif MAX==r && g>=b
            src_H(i,j)=60*(g-b)/(MAX-MIN);
       elseif MAX==r && g<b
            src_H(i,j)=60*(g-b)/(MAX-MIN)+360;
       elseif MAX==g
            src_H(i,j)=60*(b-r)/(MAX-MIN)+120;
       elseif MAX==b
            src_H(i,j)=60*(r-g)/(MAX-MIN)+240;
       end


       if MAX==0
            src_S(i,j)=0;
       else
            src_S(i,j)=1-MIN/MAX;
       end
       src_V(i,j)=MAX;
   end
end
src_S=round(src_S.*255);%扩大255倍,利于统计概率
src_V=round(src_V.*255);%扩大255倍,利于统计概率


%%读取参考图像,将其的RGB转换成HSV
tar_R=tar(:,:,1);
tar_G=tar(:,:,2);
tar_B=tar(:,:,3);
%RGB—>HSV
tar_H=zeros(m,n);   %色相角
tar_S=zeros(m,n);   %饱和度
tar_V=zeros(m,n);   %明度
for i=1:m
   for j=1:n
       r=tar_R(i,j);
       g=tar_G(i,j);
       b=tar_B(i,j);
       MAX=max([r,g,b]);
       MIN=min([r,g,b]);


       if MAX==MIN
            tar_H(i,j)=0;
       elseif MAX==r && g>=b
            tar_H(i,j)=60*(g-b)/(MAX-MIN);
       elseif MAX==r && g<b
            tar_H(i,j)=60*(g-b)/(MAX-MIN)+360;
       elseif MAX==g
            tar_H(i,j)=60*(b-r)/(MAX-MIN)+120;
       elseif MAX==b
            tar_H(i,j)=60*(r-g)/(MAX-MIN)+240;
       end


       if MAX==0
            tar_S(i,j)=0;
       else
            tar_S(i,j)=1-MIN/MAX;
       end
       tar_V(i,j)=MAX;
   end
end
tar_S=round(tar_S.*255);%扩大255倍,利于统计概率
tar_V=round(tar_V.*255);%扩大255倍,利于统计概率
%在HSV空间下进行均值方差匹配s、v层
[m_src,n_src]=size(src_S);
[m_tar,n_tar]=size(tar_S);%两幅图像都是3000*4500
srcHisto=zeros(1,256);%待匹配的直方图
tarHisto=zeros(1,256);
srcAccHisto=zeros(1,256);%待匹配的累积直方图
tarAccHisto=zeros(1,256);
 
for k=0:255   %k表示像素可以取到的S值
    count=0;  
    for i=1:m_src
        for j=1:n_src
            if(src_S(i,j)==k)
                count=count+1;
            end
        end
    end
    srcHisto(k+1)=count/(m_src*n_src);
end
srcHisto
for k=0:255   %k表示像素可以取到的灰度值
    count=0;  
    for i=1:m_tar
        for j=1:n_tar
            if(tar_S(i,j)==k)
                count=count+1;
            end
        end
    end
    tarHisto(k+1)=count/(m_tar*n_tar);
end
tarHisto
srcVal=0;
tarVal=0;
for i=1:256
    srcVal=srcVal+srcHisto(i);
    tarVal=tarVal+tarHisto(i);
    srcAccHisto(i)=srcVal;
    tarAccHisto(i)=tarVal;
end
%计算两个图像的各自的均值和方差
srcMean=0;
tarMean=0;
srcStd=0;
tarStd=0;
for j=1:256
    tarMean=tarMean+tarHisto(j)*(j-1);
    srcMean=srcMean+srcHisto(j)*(j-1);
end
tarMean
srcMean
for j=1:256
    tarStd=tarStd+(j-1-tarMean)*(j-1-tarMean)*tarHisto(j);%下标为对应的灰度级是j-1;
    srcStd=srcStd+(j-1-srcMean)*(j-1-srcMean)*srcHisto(j);
end
tarStd
srcStd
%计算映射的矩阵HistoMap(1,256),通过选择系数来构建y=kx+b
HistoMap=zeros(1,256);
s=0;sstep=0.03;minstd=9999;lev=0;
for k=0:300
    s=s+sstep;
    %移动坐标
    for j=1:256
        HistoMap(j)=(j-1-srcMean)*s+tarMean;
        if(HistoMap(j)<0)
            HistoMap(j)=0;
        end
        if(HistoMap(j)>255)
            HistoMap(j)=255;
        end
    end
    %计算中间图的方差,找出与tarStd相差最小的方差以及其对应的系数k
    srcMidStd=0;
    for j=1:256
        srcMidStd=srcMidStd+(HistoMap(j)-tarMean)*(HistoMap(j)-tarMean)*srcHisto(j);
    end
    diffstd=srcMidStd-tarStd;
    if(diffstd<minstd)
        minstd=fabs(diffstd);
        lev=k;
    end
end
%求出最终中间图的直方图HistoMap
s=sstep*lev;
for j=1:256
    HistoMap(j)=(j-1-srcMean)*s+tarMean;
    if(HistoMap(j)<0)
        HistoMap(j)=0;
    end
    if(HistoMap(j)>255)
        HistoMap(j)=255;
    end
end
%m_HistoMap=round((HistoMap*255));
src_Smatch=src_S;
for i=0:255
    src_Smatch(find(src_S==i))=HistoMap(i+1);
end
src_Smatch=double(src_Smatch);
src_Smatch=src_Smatch./255;%HSV空间下S通道的取值在0~1之间,所以要除去乘上的倍数


[m_src,n_src]=size(src_V);
[m_tar,n_tar]=size(tar_V);%两幅图像都是3000*4500
srcHisto=zeros(1,256);%待匹配的直方图
tarHisto=zeros(1,256);
srcAccHisto=zeros(1,256);%待匹配的累积直方图
tarAccHisto=zeros(1,256);
for k=0:255   %k表示像素可以取到的灰度值
    count=0;  
    for i=1:m_src
        for j=1:n_src
            if(src_V(i,j)==k)
                count=count+1;
            end
        end
    end
    srcHisto(k+1)=count/(m_src*n_src);
end
srcHisto
for k=0:255   %k表示像素可以取到的灰度值
    count=0;  
    for i=1:m_tar
        for j=1:n_tar
            if(tar_V(i,j)==k)
                count=count+1;
            end
        end
    end
    tarHisto(k+1)=count/(m_tar*n_tar);
end
tarHisto
srcVal=0;
tarVal=0;
for i=1:256
    srcVal=srcVal+srcHisto(i);
    tarVal=tarVal+tarHisto(i);
    srcAccHisto(i)=srcVal;
    tarAccHisto(i)=tarVal;
end
%计算两个图像的各自的均值和方差
srcMean=0;
tarMean=0;
srcStd=0;
tarStd=0;
for j=1:256
    tarMean=tarMean+tarHisto(j)*(j-1);
    srcMean=srcMean+srcHisto(j)*(j-1);
end
tarMean
srcMean
for j=1:256
    tarStd=tarStd+(j-1-tarMean)*(j-1-tarMean)*tarHisto(j);%下标为对应的灰度级是j-1;
    srcStd=srcStd+(j-1-srcMean)*(j-1-srcMean)*srcHisto(j);
end
tarStd
srcStd
%计算映射的矩阵HistoMap(1,256),通过选择系数来构建y=kx+b
HistoMap=zeros(1,256);
s=0;sstep=0.03;minstd=9999;lev=0;
for k=0:300
    s=s+sstep;
    %移动坐标
    for j=1:256
        HistoMap(j)=(j-1-srcMean)*s+tarMean;
        if(HistoMap(j)<0)
            HistoMap(j)=0;
        end
        if(HistoMap(j)>255)
            HistoMap(j)=255;
        end
    end
    %计算中间图的方差,找出与tarStd相差最小的方差以及其对应的系数k
    srcMidStd=0;
    for j=1:256
        srcMidStd=srcMidStd+(HistoMap(j)-tarMean)*(HistoMap(j)-tarMean)*srcHisto(j);
    end
    diffstd=srcMidStd-tarStd;
    if(diffstd<minstd)
        minstd=fabs(diffstd);
        lev=k;
    end
end
%求出最终中间图的直方图HistoMap
s=sstep*lev;
for j=1:256
    HistoMap(j)=(j-1-srcMean)*s+tarMean;
    if(HistoMap(j)<0)
        HistoMap(j)=0;
    end
    if(HistoMap(j)>255)
        HistoMap(j)=255;
    end
end
%m_HistoMap=round((HistoMap*255));
src_Vmatch=src_V;
for i=0:255
    src_Vmatch(find(src_V==i))=HistoMap(i+1);
end
src_Vmatch=double(src_Vmatch);
src_Vmatch=src_Vmatch./255;%HSV空间下V通道的取值在0~1之间,所以要除去乘上的倍数
%匹配后转换成RGB空间下的图片
H=src_H;
S=src_Smatch;
V=src_Vmatch;
R=src_R;
G=src_G;
B=src_B;
%%图像HSV2RGB
for i=1:m
    for j=1:n
        h=floor(H(i,j)/60);
        f=H(i,j)/60-h;
        v=V(i,j);
        s=S(i,j);
        p=v*(1-s);
        q=v*(1-f*s);
        t=v*(1-(1-f)*s);


        if h==0
            R(i,j)=v;G(i,j)=t;B(i,j)=p;
        elseif h==1
            R(i,j)=q;G(i,j)=v;B(i,j)=p;            
        elseif h==2
            R(i,j)=p;G(i,j)=v;B(i,j)=t;            
        elseif h==3
            R(i,j)=p;G(i,j)=q;B(i,j)=v;            
        elseif h==4
            R(i,j)=t;G(i,j)=p;B(i,j)=v;            
        elseif h==5
            R(i,j)=v;G(i,j)=p;B(i,j)=q;            
        end
    end
end


%%如果正反变换都没错的话,那么图像是不变的
img(:,:,1)=R;
img(:,:,2)=G;
img(:,:,3)=B;
figure;
imshow(img)
imwrite(img,'C:\Users\chenlong\Desktop\HSV空间\match.jpg');