Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MATLAB中的彩色图像校正_Matlab_Image Processing - Fatal编程技术网

MATLAB中的彩色图像校正

MATLAB中的彩色图像校正,matlab,image-processing,Matlab,Image Processing,我有两个图像im1和im2如下所示。IM2图片与im1相同,但它们之间的唯一区别是颜色。im1的每个颜色通道的RGB范围为0-255、0-255、0-255,而im2的RGB范围为201-255、126-255、140-255。我的练习是逆转增加的效果,以便尽可能地将im2恢复到im1。我有两个想法。第一种方法是匹配它们的直方图,使它们具有相同的颜色。我尝试使用histeq,但它只恢复了图像的一部分。有没有办法将im2的直方图更改为与im1完全相同?第二种方法只是将每个像素值从im1复制到im2

我有两个图像im1和im2如下所示。IM2图片与im1相同,但它们之间的唯一区别是颜色。im1的每个颜色通道的RGB范围为0-255、0-255、0-255,而im2的RGB范围为201-255、126-255、140-255。我的练习是逆转增加的效果,以便尽可能地将im2恢复到im1。我有两个想法。第一种方法是匹配它们的直方图,使它们具有相同的颜色。我尝试使用histeq,但它只恢复了图像的一部分。有没有办法将im2的直方图更改为与im1完全相同?第二种方法只是将每个像素值从im1复制到im2,但这是错误的,因为它无法恢复原始图像状态。是否有任何恢复图像的建议


@下面的sepdek非常推荐@NKN提到的方法,但我将提供另一种方法。我可以建议的另一种选择是基于最小均方解执行颜色校正。这意味着,我们可以假设将像素从im2转换为im1需要权重的线性组合。换句话说,给定一个RGB像素,其中其红色、绿色和蓝色分量从损坏图像im2成形为3 x 1矢量,存在一些线性变换以获得干净图像im1中的等效像素。换句话说,我们有这种关系:

[R_im1]       [R_im2]
[G_im1] = A * [G_im2]
[B_im1]       [B_im2]

  Y     = A *   X
在这种情况下,A将是一个3x3矩阵。这实质上是执行矩阵乘法以获得输出校正像素。来自im2的输入RGB像素为X,来自im1的输出RGB像素为Y。我们可以将其扩展到我们想要的任意多个像素,其中来自im1和im2的像素对将沿Y和X建立列。通常,这将进一步将X和Y扩展到3 X N矩阵。要找到矩阵A,您将找到最小均方误差解。我不想讨论它,但要找到A的最优矩阵,这需要找到伪逆。在我们这里的例子中,A因此等于:

一旦你找到这个矩阵A,你需要在你的图像中的每个像素,塑造它,使它成为一个3 x 1的向量,然后用这个向量乘以A,就像上面的方法。有一件事你可能会问自己,我需要从两幅图像中获取什么样的像素才能使上述方法起作用?您必须遵守的一条准则是,您需要确保从两个图像之间的相同空间位置采样。因此,如果我们在…上抓取一个像素。。。说第4行第9列,您需要确保来自im1和im2的两个像素都来自同一行和同一列,并且它们被放置在X和Y的相同对应列中

这种方法的另一个小警告是,您需要确保对图像中的大量像素进行采样以获得良好的解决方案,并且还需要确保采样的范围覆盖整个图像。如果我们将采样定位在一个很小的区域内,那么颜色的分布就不够好,因此输出看起来就不太好。这取决于你为问题选择了多少像素,但根据经验,你会发现输出开始平稳,你看不到任何差异。为了演示,我在整个图像中随机选择了2000个像素

因此,这就是代码的样子。我使用生成从1到M的随机排列,其中M是图像中的像素总数。这些生成线性索引,以便我们可以从图像中采样并构造矩阵。然后,我们应用上面的方程找到A,然后取每个像素,应用矩阵与A相乘得到输出。不言而喻:

close all;
clear all;
im1 = imread('http://i.stack.imgur.com/GtgHU.jpg');
im2 = imread('http://i.stack.imgur.com/wHW50.jpg');

rng(123); %// Set seed for reproducibility
num_colours = 2000;
ind = randperm(numel(im1) / size(im1,3), num_colours);

%// Grab colours from original image
red_out = im1(:,:,1);
green_out = im1(:,:,2);
blue_out = im1(:,:,3);

%// Grab colours from corrupted image
red_in = im2(:,:,1);
green_in = im2(:,:,2);
blue_in = im2(:,:,3);

%// Create 3 x N matrices
X = double([red_in(ind); green_in(ind); blue_in(ind)]);
Y = double([red_out(ind); green_out(ind); blue_out(ind)]);

%// Find A
A = Y*(X.')/(X*X.');

%// Cast im2 to double for precision
im2_double = double(im2);

%// Apply matrix multiplication    
out = cast(reshape((A*reshape(permute(im2_double, [3 1 2]), 3, [])).', ...
          [size(im2_double,1) size(im2_double,2), 3]), class(im2));
让我们慢慢地看一下这段代码。我正在直接从StackOverflow读取您的图像。之后,我使用设置种子,以便您可以在您的端复制相同的结果。设置种子非常有用,因为它允许您重现我所做的随机像素选择。我们生成这些线性指数,然后为im1和im2创建3xN矩阵。查找A正是我所描述的,但您可能不习惯rdivid//运算符。rdivide在运算符的右侧找到逆,然后将其与左侧的任何值相乘。这是一种更有效的计算方法,而不是单独计算右侧的倒数,然后在完成后与左侧相乘。事实上,MATLAB会给您一个警告,说明避免单独计算逆,而应该使用除法运算符。接下来,我将im2转换为double以确保精度,因为A很可能是浮点值,然后将每个像素与A相乘以计算结果。最后一行代码看起来很吓人,但如果你想知道我是如何 ed this,我用它来创建复古风格的照片,这也需要矩阵乘法,就像这种方法一样,你可以在这里阅读:。我们的最终形象。运行此代码并显示输出结果后,我们得到以下结果:

现在,输出看起来完全混乱,但颜色分布或多或少地模仿了输入原始图像的样子。我对这种情况的原因有一些解释:

存在量化噪声。如果你看最后一张图片,你会发现到处都是各种各样的白色斑点。这可能是由于压缩图像时引入的量化错误造成的。在图像之间映射到相同颜色的像素会有轻微的变化,这是因为量化给了我们这种定位 im2中映射到im1的颜色不止一种。如果从im2映射到im1的颜色不止一种,则在给定im2中的单个像素的情况下,与矩阵a的线性乘法不可能为im1生成多种颜色。取而代之的是,最小均方解将尝试生成一种使误差最小化的颜色,并为您提供尽可能最好的颜色。这可能就是因为这个确切的原因,脸部和图像的其他细节被模糊的方式。 图像有噪声。你的im2不是完全干净的。我还可以在所有的频道上看到各种各样的椒盐噪音。这种方法的一个缺点是,如果图像受到噪声的影响,那么这种方法将无法正确地重建原始图像。您的图像只能被错误的颜色映射损坏。如果引入了任何其他类型的图像噪声,则此方法肯定不起作用,因为您试图基于噪声图像重建原始图像。噪声图像中存在原始图像中从未出现过的像素,因此您将无法将其恢复到以前的状态! 如果您想查看原始图像和输出图像之间每个通道的直方图,我们将得到:

我用来生成上图的代码是:

names = {'Red', 'Green', 'Blue'};
figure;
for idx = 1 : 3
    subplot(3,2,2*idx - 1);
    imhist(im1(:,:,idx));
    title([names{idx} ': Image 1']);
end

for idx = 1 : 3
    subplot(3,2,2*idx);
    imhist(out(:,:,idx));
    title([names{idx} ': Output']);
end
左侧显示原始图像的红色、绿色和蓝色直方图,而右侧显示重建图像的相同直方图。您可以看到,一般形状或多或少地模仿了原始图像,但始终存在一些尖峰-最有可能归因于量化噪声和两幅图像颜色之间的非唯一映射

总而言之,这是我能做的最好的了,但我认为这是整个练习的重点。。。。表明这是不可能的

有关如何执行颜色校正的更多信息,请查看。这是我开始的,如何计算A的推导可以在他的幻灯片中找到。也许你可以在将来的工作中使用他所说的一些东西


祝你好运

似乎需要一个缩放函数来将im2的值映射到im1的值。 这相当简单,您可以编写一个缩放函数,使其适用于任何此类情况。 基本比例映射的工作原理如下:

out_value = min_output + (in_value - min_input) * (outrange / inrange)
假设有一个输入值在范围inrange=max\U input-min\U input的值范围内,并且映射结果是输出值out\U值在范围outrange=max\U output-min\U output内。我们还需要考虑最小输入和输出范围界限min_input和min_output,以获得正确的映射。 有关缩放函数的示例,请参见以下代码:

%
% scale the values of a matrix using a set of limits
% possible ways to use:
% y = scale( x, in_range, out_range)  --> ex. y = scale( x, [8 230], [0 255])
% y = scale( x, out_range)            --> ex. y = scale( x, [0 1])
% 
function y = scale( x, varargin );
    if nargin<2,
        error([upper(mfilename),':: Syntax: y=',mfilename,'(x[,in_range],out_range)']);
    end;
    if nargin==2,
        inrange=[min(x(:)) max(x(:))];      % compute the limits of the input variable
        outrange=varargin{1};               % get the output limits from the arguments
    else
        inrange=varargin{1};                % get the input limits from the arguments
        outrange=varargin{2};               % get the output limits from the arguments
    end;

    if diff(inrange)==0,                    % row or column vector matrix or scalar
        % just do a clipping...
        if x>=outrange(2), 
            y=outrange(2); 
        elseif x<=outrange(1), 
            y=outrange(1); 
        else 
            y=x; 
        end;
    else
        % actually scale the data
        % using: out = min_output + (x-min_input) * (outrange / inrange)
        y = outrange(1) + (x-inrange(1))*abs(diff(outrange))/abs(diff(inrange));
    end;

通过这种方式,每次将im2缩放到一个通道im1的值范围。输出变量img应该是所需的。

难道不能使用color1和color2之间的线性映射吗?当你说线性映射时,你指的是im2矩阵的每个像素值复制到im1?这只是复制粘贴还是不复制粘贴?不,从im2得到一个值,比如r=220。您希望将其映射到范围im1中的值。你可以通过建立一个线性方程来映射它。这不是复制粘贴。哇,谢谢你,伙计,你能解释一下你所说的线性方程是什么意思吗?如果我没弄错的话,映射在im11,1,1的像素应该和在1,1,1的im2像素的颜色相同?@KostasRim-不。你只是把颜色从im1复制到im2。我会写一个答案。谢谢你的回答,最终的图像不像im1。我使用imhist来比较out和im1中每个香奈儿的rgb颜色。rgb颜色的分布似乎在[0-255]范围内,但不像im1颜色那样恢复。im1的直方图与im2完全不同。这是相同的图像,但im2是redish。有什么建议吗?顺便说一句,它没有将rgb颜色调整到0-255的范围,这是一个加号。我现在唯一需要找到的是如何更改直方图以匹配彼此的…@KostasRim-如果你真的发布了这些图像,这会有所帮助。这将阻止我和其他人停止猜测。
另外,您确定正确执行了直方图匹配吗?这三个频道你都是分开做的吗?试试我的编辑,看看。@KostasRim-也许可以使用颜色规格化和直方图匹配的组合?试着先做我的建议,然后是我编辑中的其他建议,看看你得到了什么。首先我想感谢你提供的所有好信息。对于我们现在的主题,我以前使用过histeq,但它不起作用。我再次尝试了histeq,并进行了imhist论证,直方图有点匹配,但颜色不对。我会把这两张照片贴出来,这样你可以告诉我你的想法。顺便说一句,im2增加了噪音。别担心,我知道如何移除它;pi还去除了噪声,第二幅图像是im2!谢谢你的回答,我试图缩放它,但结果图像与im1不一样。@KostasRim你确定你做对了吗?我已经测试过了,效果很好。所有表都是双精度[0…255]。双人是必须的。根据数值的不同,可能会由于除法而产生舍入错误,但应该出现在第9个++位。@KostasRim好的,现在我看到了您在问题中包含的图像,我相信问题要复杂得多。一般来说,如果您了解导致图像退化的初始变换,并且该变换是可逆的,则可以将其反转,考虑到数据的整数性质导致的量化误差,但如果你不知道退化映射,包括你不知道它是线性的,那么假设线性变换来反转它是不够的……是的,我不知道是什么变换导致了最终的图像。关键是要扭转这种局面。我发现了两种方法,首先是使用HiStq为每个颜色通道。输出照片是相当好的,非常接近IM1颜色,但略微发亮在中间。尽管柱状图不是很接近。另一种方法是发布在这里的方法。颜色和直方图变得相似,但与图像不同。我将把这两个答案都包括在我的练习中,并希望我能得到一个好成绩:。谢谢
for i=1:size(im1,3),        % for each of the input/output image channels
    output_range = [min(min(im1(:,:,i))) max(max(im1(:,:,i)))];
    img(:,:,i) = scale( im2(:,:,i), output_range);
end;