在看imadjust代码时,看到stretchlim函数,特此分析一下,代码注释如下
function lowhigh = stretchlim(varargin) %STRETCHLIM Find limits to contrast stretch an image. % LOW_HIGH = STRETCHLIM(I,TOL) returns a pair of gray values that can be % used by IMADJUST to increase the contrast of an image. % % TOL = [LOW_FRACT HIGH_FRACT] specifies the fraction of the image to % saturate at low and high pixel values. % % If TOL is a scalar, TOL = LOW_FRACT, and HIGH_FRACT = 1 - LOW_FRACT, % which saturates equal fractions at low and high pixel values. % % If you omit the argument, TOL defaults to [0.01 0.99], saturating 2%. % % If TOL = 0, LOW_HIGH = [min(I(:)); max(I(:))]. % % LOW_HIGH = STRETCHLIM(RGB,TOL) returns a 2-by-3 matrix of pixel value % pairs to saturate each plane of the RGB image. TOL specifies the same % fractions of saturation for each plane. % % Class Support % ------------- % The input image can be uint8, uint16, int16, double, or single, and must % be real and nonsparse. The output limits are double and have values % between 0 and 1. % % Note % ---- % If TOL is too big, such that no pixels would be left after saturating % low and high pixel values, then STRETCHLIM returns [0; 1]. % % Example % ------- % I = imread('pout.tif'); % J = imadjust(I,stretchlim(I),[]); % figure, imshow(I), figure, imshow(J) % % See also BRIGHTEN, DECORRSTRETCH, HISTEQ, IMADJUST. % Copyright 1999-2005 The MathWorks, Inc. % $Revision: 1.7.4.8 $ $Date: 2005/11/15 01:02:11 $ [img,tol] = ParseInputs(varargin{:}); if isa(img,'uint8') nbins = 256; else nbins = 65536; end tol_low = tol(1); tol_high = tol(2); % 获取第三维的维数 p = size(img,3); if tol_low < tol_high ilowhigh = zeros(2,p); % 对于第三维的每一层进行寻找 for i = 1:p % Find limits, one plane at a time N = imhist(img(:,:,i),nbins); cdf = cumsum(N)/sum(N); %cumulative distribution function ilow = find(cdf > tol_low, 1, 'first'); %找到满足累计频率>tol_low的下标 ihigh = find(cdf >= tol_high, 1, 'first'); %找到满足累计频率>=tol_low的下标 if ilow == ihigh % this could happen if img is flat ilowhigh(:,i) = [1;nbins]; else ilowhigh(:,i) = [ilow;ihigh]; end end lowhigh = (ilowhigh - 1)/(nbins-1); % convert to range [0 1] else % tol_low >= tol_high, this tolerance does not make sense. For example, if % the tolerance is .5 then no pixels would be left after saturating % low and high pixel values. In all of these cases, STRETCHLIM % returns [0; 1]. See gecks 278249 and 235648. lowhigh = repmat([0;1],1,p); end %----------------------------------------------------------------------------- function [img,tol] = ParseInputs(varargin) iptchecknargin(1, 2, nargin, mfilename); img = varargin{1}; iptcheckinput(img, {'uint8', 'uint16', 'double', 'int16', 'single'}, {'real', ... 'nonsparse'}, mfilename, 'I or RGB', 1); if (ndims(img) > 3) msgId = 'Images:stretchlim:dimTooHigh'; error(msgId,'STRETCHLIM only supports individual images.'); end % 默认值 tol = [.01 .99]; %default if nargin == 2 tol = varargin{2}; switch numel(tol) %判断tol数组元素个数 case 1 tol(2) = 1 - tol; case 2 if (tol(1) >= tol(2)) msgId = 'Images:stretchlim:invalidTolOrder'; error(msgId,'TOL(1) must be less than TOL(2).'); end otherwise msgId = 'Images:stretchlim:invalidTolSize'; error(msgId,'TOL must have 1 or 2 elements.'); end end if ( any(tol < 0) || any(tol > 1) || any(isnan(tol)) ) msgId = 'Images:stretchlim:tolOutOfRange'; error(msgId,'TOL must be in the range [0 1].'); end
主函数为stretchlim,其中子函数ParseInputs用于获取参数。
主函数中关键部分为
if tol_low < tol_high ilowhigh = zeros(2,p); % 对于第三维的每一层进行寻找 for i = 1:p % Find limits, one plane at a time N = imhist(img(:,:,i),nbins); cdf = cumsum(N)/sum(N); %cumulative distribution function ilow = find(cdf > tol_low, 1, 'first'); %找到满足累计频率>tol_low的下标 ihigh = find(cdf >= tol_high, 1, 'first'); %找到满足累计频率>=tol_low的下标 if ilow == ihigh % this could happen if img is flat ilowhigh(:,i) = [1;nbins]; else ilowhigh(:,i) = [ilow;ihigh]; end end lowhigh = (ilowhigh - 1)/(nbins-1); % convert to range [0 1]
函数imhist是用于获取图像数据直方图,返回值是个一维矩阵,保存着图像中每个灰度等级的像素个数,如上,如果nbins等于256,代表灰度范围为0~255,则imhist获取图像img中符合每个灰度等级的像素个数,例如灰度等级3对应数组N下标4,图像中灰度等级为3的像素个数为5,则N(4)=5。
cdf = cumsum(N)/sum(N);
这一行中cumsum(N)计算一个数组各个元素的累加值,例如数组 N = [1 3 5],则cumsum(N) = [1 4 9],sum(N)获取数组N的元素个数,因此这个式子代表意思是每个灰度等级的累积频率,例子中sum(N)=3,则cdf=[1/3 4/3 9/3]。
ilow = find(cdf > tol_low, 1, 'first'); %找到满足累计频率>tol_low的下标 ihigh = find(cdf >= tol_high, 1, 'first'); %找到满足累计频率>=tol_low的下标
找到下标ilow和ihigh,可对应满足条件的灰度等级,因为cdf数组中下标也就是对应灰度等级的值加1。
lowhigh = (ilowhigh - 1)/(nbins-1); % convert to range [0 1]
归一化,将范围[ilow ihigh]映射到[0 1]