聲明:本文涉及到的行數皆指本文提供的附件imadjust.m的代碼中行數
本文只討論imadjust函數是一種用法,即
J = IMADJUST(I,[LOW_IN; HIGH_IN],[LOW_OUT; HIGH_OUT],GAMMA)
處理效果如下圖
圖像矩陣I要求數據類型uint8、uint16、double、single和int16,[LOW_IN HIGH_IN]和[LOW_OUT HIGH_OUT] 要求范圍都要在[0 1]區間中,不然會出問題。
1.函數首先獲得輸入參數(行97)
[img,imageType,lowIn,highIn,lowOut,highOut,gamma] = ...
parseInputs(varargin{:});
根據用法
J = IMADJUST(I,[LOW_IN; HIGH_IN],[LOW_OUT; HIGH_OUT],GAMMA)
其中I賦值給img,imgeType后續有說明,LOW_IN賦值給lowIn,HIGH_IN賦值給highIn,LOW_OUT賦值給lowOUt,HIGH_OUT賦值給highOut,GAMMA賦值給gamma。
進入子函數paraseInputs(行196)
函數會判斷輸出參數個數多少,本文主要討論參數個數>1,從行231看起

if nargin == 1 %如果輸入參數個數為1 % IMADJUST(I) if ndims(img) ~= 2 % 圖像矩陣維數不為2 eid = sprintf('Images:%s:oneArgOnlyGrayscale',mfilename); error(eid, ... 'IMADJUST(I) is only supported for 2-D grayscale images.'); end % 檢驗圖像矩陣數據類型是否double、uint8、uint16、int16和single iptcheckinput(img, {'double' 'uint8' 'uint16' 'int16' 'single'}, ... {'2d'}, mfilename, 'I', 1); % If a user passes in a m-by-3 double array, assume it is an intensity % image (there is really no way to tell). imageType = 'intensity'; % Turn off warning 'Images:imhistc:inputHasNans' before calling STRETCHLIM and % restore afterwards. STRETCHLIM calls IMHIST/IMHISTC and the warning confuses % a user who calls IMADJUST with NaNs. s = warning('off','Images:imhistc:inputHasNaNs'); lowhigh_in = stretchlim(img); warning(s) else % 如果輸入參數個數不為1 if nargin == 2 %如果輸入參數個數為2 % IMADJUST(I,[LOW_IN HIGH_IN]) % IMADJUST(MAP,[LOW_IN HIGH_IN]) % IMADJUST(RGB,[LOW_IN HIGH_IN]) if ~isempty(varargin{2}) %如果輸入參數2的數組不為空 lowhigh_in = varargin{2}; end elseif nargin == 3 %如果輸入參數個數為3 % IMADJUST(I,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT]) % IMADJUST(MAP,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT]) % IMADJUST(RGB,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT]) if ~isempty(varargin{2}) lowhigh_in = varargin{2}; end if ~isempty(varargin{3}) lowhigh_out = varargin{3}; end else %如果輸入參數個數為4 % IMADJUST(I,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT],GAMMA) % IMADJUST(MAP,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT],GAMMA) % IMADJUST(RGB,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT],GAMMA) if ~isempty(varargin{2}) lowhigh_in = varargin{2}; end if ~isempty(varargin{3}) lowhigh_out = varargin{3}; end if ~isempty(varargin{4}) gamma = varargin{4}; end end imageType = findImageType(img, lowhigh_in, lowhigh_out); checkRange(lowhigh_in, imageType, 2,'[LOW_IN; HIGH_IN]'); checkRange(lowhigh_out, imageType, 3,'[LOW_OUT; HIGH_OUT]'); end
這個if-else語句代碼很明顯看到函數輸入參數[LOW_IN HIGH_IN]賦值給了lowhigh_in,參數[LOW_OUT HIGH_OUT]賦值給了lowhigh_out,而參數GAMMA賦值給了gamma,然后執行參數有效性判斷。(行265)
imageType = findImageType(img, lowhigh_in, lowhigh_out); checkRange(lowhigh_in, imageType, 2,'[LOW_IN; HIGH_IN]'); checkRange(lowhigh_out, imageType, 3,'[LOW_OUT; HIGH_OUT]');
第一個語句主要用於根據輸入圖像矩陣判斷圖像類型,第二個和第三個主要是判斷[LOW_IN HIGH_IN]和[LOW_OUT HIGH_OUT]的正確性。
(1)findImageType函數如下(行274)

function imageType = findImageType(img, lowhigh_in, lowhigh_out) if (ndims(img)==3 && size(img,3)==3) % RGB image % RGB圖像 第三維的維數為3 iptcheckinput(img, {'double' 'uint8' 'uint16' 'int16' 'single'}, ... {}, mfilename, 'RGB1', 1); imageType = 'truecolor'; elseif (numel(lowhigh_in) == 2 && numel(lowhigh_out) == 2) || ... size(img,2) ~= 3 % Assuming that a user passed in an intensity image if lowhigh_in and % lowhigh_out are 2-element vectors, e.g., imadjust(3 column image, % [1;2], [2;3]). % 輸入圖像矩陣維數中列數不為3 iptcheckinput(img, {'double' 'uint8' 'uint16' 'int16' 'single'}, ... {'2d'}, mfilename, 'I', 1); imageType = 'intensity'; else %Colormap iptcheckmap(img,mfilename,'MAP',1); imageType = 'indexed'; end
圖像類型分為三種,第一種是'truecolor'圖像,第二種是'intensity',第三種為'indexed'。本文討論的為第二種(一般情況使用的就是第二種,其他的目前沒遇到,后續文章更新),即'intensity',判定第二種條件為[LOW_IN HIGH_IN]和[LOW_OUT HIGH_OUT]的元素個數為2並且輸入圖像矩陣列數不為3。
(2)chackRange函數如下(行300)

function checkRange(range, imageType, argumentPosition, variableName) if strcmp(imageType, 'intensity') if numel(range) ~= 2 eid = sprintf('Images:%s:InputMustBe2ElVec',mfilename); error(eid, ... 'Function %s expected its %s input argument, %s\n%s', ... mfilename, iptnum2ordinal(argumentPosition), variableName, ... 'to be a two-element vector.'); end else if ~(numel(range) == 2 || isequal(size(range), [2 3])) eid = sprintf('Images:%s:InputMustBe2ElVecOr2by3Matrix',mfilename); error(eid, ... 'Function %s expected its %s input argument, %s\n%s', ... mfilename, iptnum2ordinal(argumentPosition), variableName, ... 'to be a two-element vector or a 2-by-3 matrix.'); end end
前面判定圖像為'intensity',這里主要判斷[LOW_IN HIGH_IN]和[LOW_OUT HIGH_OUT]元素個數必須為2,不然報錯,這里就是第一個檢查,后面還有檢查。
最后
[low_in high_in] = splitRange(lowhigh_in, imageType);
[low_out high_out] = splitRange(lowhigh_out, imageType);
獲取參數[low_in high_in] 和 [low_out high_out] ,然后函數返回。
2.參數檢查
前面通過函數paraseInputs獲取了用戶輸入的參數,接下來進行參數有效性檢驗
validateLowHigh(lowIn,highIn,lowOut,highOut);
gamma = validateGamma(gamma,imageType);
(1)函數validateLowHigh(行340)

function validateLowHigh(lowIn,highIn,lowOut,highOut) if any(lowIn >= highIn) eid = sprintf('Images:%s:lowMustBeSmallerThanHigh',mfilename); error(eid, '%s: LOW_IN must be less than HIGH_IN.',... upper(mfilename)); end if isInvalidRange(lowIn) || isInvalidRange(highIn) ... || isInvalidRange(lowOut) || isInvalidRange(highOut) eid = sprintf('Images:%s:parametersAreOutOfRange',mfilename); error(eid, '%s: LOW_IN, HIGH_IN, LOW_OUT and HIGH_OUT %s',... upper(mfilename), 'must be in the range [0.0, 1.0].'); end
該函數首先檢查了lowIn要小於highIn,但是沒要求lowOut要小於highOut,因為這個函數有個運用,在於可以反轉圖像,即[0 1]變換到[1 0]。
然后使用函數isInvalidRange限制了輸入lowIn、highIn、lowOut和highOut范圍為[0 1],這就是開頭所說[LOW_IN HIGH_IN]和[LOW_OUT HIGH_OUT] 要求范圍都要在[0 1]區間中的出處。
(2)函數validateGamma(行362)

function gamma = validateGamma(gamma,image_type) if strcmp(image_type,'intensity') iptcheckinput(gamma,{'double'},{'scalar', 'nonnegative'}, ... mfilename, 'GAMMA', 4) else iptcheckinput(gamma,{'double'},{'nonnegative','2d'},... mfilename, 'GAMMA', 4) if numel(gamma) == 1, gamma = gamma*ones(1,3); end end
前面判定圖像類型為'intensity',這里判定gamma參數必須為正數。
3.執行變換(行104)

if ~isfloat(img) && numel(img) > 65536 % integer data type image with more than 65536 elements out = adjustWithLUT(img,lowIn,highIn,lowOut,highOut,gamma); else classin = class(img); classChanged = false; if ~isa(img,'double') %如果圖像矩陣數據類型不為double, 圖像矩陣數據范圍轉為[0,1] classChanged = true; img = im2double(img); end if strcmp(imageType, 'intensity') out = adjustGrayscaleImage(img,lowIn,highIn,lowOut,highOut,gamma); elseif strcmp(imageType, 'indexed') out = adjustColormap(img,lowIn,highIn,lowOut,highOut,gamma); else out = adjustTruecolorImage(img,lowIn,highIn,lowOut,highOut,gamma); end if classChanged out = changeclass(classin,out); end end
首先判斷如果圖像矩陣數據不為浮點數(double和single)並且矩陣元素個數>65536,則執行函數adjustWithLUT函數。
(1)adjustWithLUT函數如下

function out = adjustWithLUT(img,lowIn,highIn,lowOut,highOut,gamma) imgClass = class(img); out = zeros(size(img),imgClass); %initialize for lut switch imgClass case 'uint8' lutLength = 256; conversionFcn = @im2uint8; case 'uint16' lutLength = 65536; conversionFcn = @im2uint16; case 'int16' lutLength = 65536; conversionFcn = @im2int16; otherwise eid = sprintf('Images:%s:internalError',mfilename); msg = 'Internal error: invalid class type.'; error(eid,'%s',msg); end
關鍵部分
for p = 1:size(img,3) lut = linspace(0,1,lutLength); scalingFactor = 1; lut = adjustArray(lut,lowIn(p),highIn(p),lowOut(p),highOut(p), ... gamma(p),scalingFactor); lut = conversionFcn(lut); out(:,:,p) = intlut(img(:,:,p),lut); end
首先創建一個數組作為篩選數組,不需要對圖像矩陣進行變換,直接根據篩選數組的篩選圖像矩陣。以下語句為灰度值歸一化,將灰度歸一化到[0 1]范圍,這是為了后面變換方便。
lut = linspace(0,1,lutLength);
lutLength的大小為圖像矩陣數據類型對應該類型的最大值,例如圖像矩陣數據類型為uint8,則lutLength=256。該語句作用在於創建一個數組lut,數組儲存歸一化后的灰度值,每個元素分別對於相應的灰度等級。
lut = adjustArray(lut,lowIn(p),highIn(p),lowOut(p),highOut(p), ...
gamma(p),scalingFactor);
對lut進行變換,變換結果如開頭的圖
lowIn=低輸入 highIn=高輸入 lowOut=低輸出 highOut=高輸出
由於數組lut元素范圍[0 1],這是歸一化數據,因此要還原對應的值
lut = conversionFcn(lut);
剩下就是篩選了
out(:,:,p) = intlut(img(:,:,p),lut);
(2)adjustArray函數(行187)
function out = adjustArray(img,lIn,hIn,lOut,hOut,g,d) %make sure img is in the range [lIn;hIn] img(:) = max(lIn(d,:), min(hIn(d,:),img)); out = ( (img - lIn(d,:)) ./ (hIn(d,:) - lIn(d,:)) ) .^ (g(d,:)); out(:) = out .* (hOut(d,:) - lOut(d,:)) + lOut(d,:);
首先篩選掉矩陣img中小於lIn的數的數值變為lIn,大於hIn的數的數值變為hIn,篩選語句如下
img(:) = max(lIn(d,:), min(hIn(d,:),img));
接着進行變換,令 並且d=1,則該函數處理的效果等價於:
至於為什么這樣,我手寫推導過程如下
表達式就是曲線AB的方程
附件:imadjust.m代碼

1 function out = imadjust(varargin) 2 %IMADJUST Adjust image intensity values or colormap. 3 % J = IMADJUST(I) maps the values in intensity image I to new values in J 4 % such that 1% of data is saturated at low and high intensities of I. 5 % This increases the contrast of the output image J. 6 % 7 % J = IMADJUST(I,[LOW_IN; HIGH_IN],[LOW_OUT; HIGH_OUT]) maps the values 8 % in intensity image I to new values in J such that values between LOW_IN 9 % and HIGH_IN map to values between LOW_OUT and HIGH_OUT. Values below 10 % LOW_IN and above HIGH_IN are clipped; that is, values below LOW_IN map 11 % to LOW_OUT, and those above HIGH_IN map to HIGH_OUT. You can use an 12 % empty matrix ([]) for [LOW_IN; HIGH_IN] or for [LOW_OUT; HIGH_OUT] to 13 % specify the default of [0 1]. If you omit the argument, [LOW_OUT; 14 % HIGH_OUT] defaults to [0 1]. 15 % 16 % J = IMADJUST(I,[LOW_IN; HIGH_IN],[LOW_OUT; HIGH_OUT],GAMMA) maps the 17 % values of I to new values in J as described in the previous syntax. 18 % GAMMA specifies the shape of the curve describing the relationship 19 % between the values in I and J. If GAMMA is less than 1, the mapping is 20 % weighted toward higher (brighter) output values. If GAMMA is greater 21 % than 1, the mapping is weighted toward lower (darker) output values. If 22 % you omit the argument, GAMMA defaults to 1 (linear mapping). 23 % 24 % NEWMAP = IMADJUST(MAP,[LOW_IN; HIGH_IN],[LOW_OUT; HIGH_OUT],GAMMA) 25 % transforms the colormap associated with an indexed image. If LOW_IN, 26 % HIGH_IN, LOW_OUT, HIGH_OUT, and GAMMA are scalars, then the same 27 % mapping applies to red, green and blue components. Unique mappings for 28 % each color component are possible when: LOW_IN and HIGH_IN are both 29 % 1-by-3 vectors, LOW_OUT and HIGH_OUT are both 1-by-3 vectors, OR GAMMA 30 % is a 1-by-3 vector. The rescaled colormap, NEWMAP, is the same size as 31 % MAP. 32 % 33 % RGB2 = IMADJUST(RGB1,...) performs the adjustment on each image plane 34 % (red, green, and blue) of the RGB image RGB1. As with the colormap 35 % adjustment, you can apply unique mappings to each plane. 36 % 37 % Note that IMADJUST(I) is equivalent to IMADJUST(I,STRETCHLIM(I)). 38 % 39 % Note that if HIGH_OUT < LOW_OUT, the output image is reversed, as in a 40 % photographic negative. 41 % 42 % Class Support 43 % ------------- 44 % For syntaxes that include an input image (rather than a colormap), the 45 % input image can be uint8, uint16, int16, double, or single. The output 46 % image has the same class as the input image. For syntaxes that include 47 % a colormap, the input and output colormaps are double. 48 % 49 % Examples 50 % -------- 51 % I = imread('pout.tif'); 52 % J = imadjust(I); 53 % figure, imshow(I), figure, imshow(J) 54 % 55 % K = imadjust(I,[0.3 0.7],[]); 56 % figure, imshow(K) 57 % 58 % RGB1 = imread('football.jpg'); 59 % RGB2 = imadjust(RGB1,[.2 .3 0; .6 .7 1],[]); 60 % figure, imshow(RGB1), figure, imshow(RGB2) 61 % 62 % See also BRIGHTEN, DECORRSTRETCH, HISTEQ, IMCONTRAST, STRETCHLIM. 63 64 % Copyright 1992-2007 The MathWorks, Inc. 65 % $Revision: 5.26.4.9 $ $Date: 2007/12/10 21:37:18 $ 66 67 % Input-output specs 68 % ------------------ 69 % I,J real, full matrix, 2-D 70 % uint8, uint16, double, single, int16 71 % 72 % RGB1,RGB2 real, full matrix 73 % M-by-N-by-3 74 % uint8, uint16, double, single, int16 75 % 76 % MAP,NEWMAP real, full matrix 77 % M-by-3 78 % double with values in the range [0,1]. 79 % 80 % [LOW_IN; HIGH_IN] double, real, full matrix 81 % For I, size can only be 2 elements. 82 % For RGB or MAP, size can be 2 elements OR 83 % 2-by-3 matrix. 84 % LOW_IN < HIGH_IN 85 % 86 % [LOW_OUT; HIGH_OUT] Same size restrictions as [LOW_IN; HIGH_IN] 87 % LOW_OUT can be less than HIGH_OUT 88 % 89 % LOW_IN, HIGH_IN, LOW_OUT, HIGH_OUT all must be in the range [0,1]; 90 % 91 % GAMMA real, double, nonnegative 92 % scalar for I 93 % scalar or 1-by-3 vector for RGB and MAP 94 95 96 97 %Parse inputs and initialize variables 98 [img,imageType,lowIn,highIn,lowOut,highOut,gamma] = ... 99 parseInputs(varargin{:}); 100 101 validateLowHigh(lowIn,highIn,lowOut,highOut); 102 gamma = validateGamma(gamma,imageType); 103 104 if ~isfloat(img) && numel(img) > 65536 105 % integer data type image with more than 65536 elements 106 out = adjustWithLUT(img,lowIn,highIn,lowOut,highOut,gamma); 107 108 else 109 classin = class(img); 110 classChanged = false; 111 if ~isa(img,'double') %如果圖像矩陣數據類型不為double, 圖像矩陣數據范圍轉為[0,1] 112 classChanged = true; 113 img = im2double(img); 114 end 115 116 if strcmp(imageType, 'intensity') 117 out = adjustGrayscaleImage(img,lowIn,highIn,lowOut,highOut,gamma); 118 elseif strcmp(imageType, 'indexed') 119 out = adjustColormap(img,lowIn,highIn,lowOut,highOut,gamma); 120 else 121 out = adjustTruecolorImage(img,lowIn,highIn,lowOut,highOut,gamma); 122 end 123 124 if classChanged 125 out = changeclass(classin,out); 126 end 127 128 end 129 130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 131 function out = adjustWithLUT(img,lowIn,highIn,lowOut,highOut,gamma) 132 133 imgClass = class(img); 134 out = zeros(size(img),imgClass); 135 136 %initialize for lut 137 138 switch imgClass 139 case 'uint8' 140 lutLength = 256; 141 conversionFcn = @im2uint8; 142 case 'uint16' 143 lutLength = 65536; 144 conversionFcn = @im2uint16; 145 case 'int16' 146 lutLength = 65536; 147 conversionFcn = @im2int16; 148 otherwise 149 eid = sprintf('Images:%s:internalError',mfilename); 150 msg = 'Internal error: invalid class type.'; 151 error(eid,'%s',msg); 152 end 153 154 for p = 1:size(img,3) 155 lut = linspace(0,1,lutLength); 156 scalingFactor = 1; 157 lut = adjustArray(lut,lowIn(p),highIn(p),lowOut(p),highOut(p), ... 158 gamma(p),scalingFactor); 159 lut = conversionFcn(lut); 160 out(:,:,p) = intlut(img(:,:,p),lut); 161 end 162 163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 164 function out = adjustColormap(cmap,lIn,hIn,lOut,hOut,g) 165 166 % expansion factor that can expand a 1-by-3 range to the size of cmap. 167 expansionFactor = ones(size(cmap,1), 1); 168 out = adjustArray(cmap, lIn, hIn, lOut, hOut, g, expansionFactor); 169 170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 171 function out = adjustGrayscaleImage(img,lIn,hIn,lOut,hOut,g) 172 173 expansionFactor = 1; 174 out = adjustArray(img, lIn, hIn, lOut, hOut, g, expansionFactor); 175 176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 177 function out = adjustTruecolorImage(rgb,lIn,hIn,lOut,hOut,g) 178 179 out = zeros(size(rgb), class(rgb)); 180 expansionFactor = 1; 181 for p = 1 : 3 182 out(:,:,p) = adjustArray(rgb(:,:,p), lIn(p),hIn(p), lOut(p), ... 183 hOut(p), g(p), expansionFactor); 184 end 185 186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 187 function out = adjustArray(img,lIn,hIn,lOut,hOut,g,d) 188 189 %make sure img is in the range [lIn;hIn] 190 img(:) = max(lIn(d,:), min(hIn(d,:),img)); 191 192 out = ( (img - lIn(d,:)) ./ (hIn(d,:) - lIn(d,:)) ) .^ (g(d,:)); 193 out(:) = out .* (hOut(d,:) - lOut(d,:)) + lOut(d,:); 194 195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 196 % 參數獲取 197 function [img,imageType,low_in,high_in,low_out,high_out,gamma] = ... 198 parseInputs(varargin) 199 200 iptchecknargin(1,4,nargin,mfilename); % 輸入參數個數在1-4個 201 img = varargin{1}; % img保存圖像矩陣 202 203 204 % Default values (默認值) 205 lowhigh_in = [0; 1]; 206 lowhigh_out = [0; 1]; 207 gamma = 1; 208 209 if nargin == 1 %如果輸入參數個數為1 210 % IMADJUST(I) 211 if ndims(img) ~= 2 % 圖像矩陣維數不為2 212 eid = sprintf('Images:%s:oneArgOnlyGrayscale',mfilename); 213 error(eid, ... 214 'IMADJUST(I) is only supported for 2-D grayscale images.'); 215 end 216 % 檢驗圖像矩陣數據類型是否double、uint8、uint16、int16和single 217 iptcheckinput(img, {'double' 'uint8' 'uint16' 'int16' 'single'}, ... 218 {'2d'}, mfilename, 'I', 1); 219 220 % If a user passes in a m-by-3 double array, assume it is an intensity 221 % image (there is really no way to tell). 222 imageType = 'intensity'; 223 224 % Turn off warning 'Images:imhistc:inputHasNans' before calling STRETCHLIM and 225 % restore afterwards. STRETCHLIM calls IMHIST/IMHISTC and the warning confuses 226 % a user who calls IMADJUST with NaNs. 227 s = warning('off','Images:imhistc:inputHasNaNs'); 228 lowhigh_in = stretchlim(img); 229 warning(s) 230 231 else % 如果輸入參數個數不為1 232 if nargin == 2 %如果輸入參數個數為2 233 % IMADJUST(I,[LOW_IN HIGH_IN]) 234 % IMADJUST(MAP,[LOW_IN HIGH_IN]) 235 % IMADJUST(RGB,[LOW_IN HIGH_IN]) 236 if ~isempty(varargin{2}) %如果輸入參數2的數組不為空 237 lowhigh_in = varargin{2}; 238 end 239 240 elseif nargin == 3 %如果輸入參數個數為3 241 % IMADJUST(I,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT]) 242 % IMADJUST(MAP,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT]) 243 % IMADJUST(RGB,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT]) 244 245 if ~isempty(varargin{2}) 246 lowhigh_in = varargin{2}; 247 end 248 if ~isempty(varargin{3}) 249 lowhigh_out = varargin{3}; 250 end 251 else %如果輸入參數個數為4 252 % IMADJUST(I,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT],GAMMA) 253 % IMADJUST(MAP,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT],GAMMA) 254 % IMADJUST(RGB,[LOW_IN HIGH_IN],[LOW_OUT HIGH_OUT],GAMMA) 255 if ~isempty(varargin{2}) 256 lowhigh_in = varargin{2}; 257 end 258 if ~isempty(varargin{3}) 259 lowhigh_out = varargin{3}; 260 end 261 if ~isempty(varargin{4}) 262 gamma = varargin{4}; 263 end 264 end 265 imageType = findImageType(img, lowhigh_in, lowhigh_out); 266 checkRange(lowhigh_in, imageType, 2,'[LOW_IN; HIGH_IN]'); 267 checkRange(lowhigh_out, imageType, 3,'[LOW_OUT; HIGH_OUT]'); 268 end 269 270 [low_in high_in] = splitRange(lowhigh_in, imageType); 271 [low_out high_out] = splitRange(lowhigh_out, imageType); 272 273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 274 function imageType = findImageType(img, lowhigh_in, lowhigh_out) 275 276 if (ndims(img)==3 && size(img,3)==3) 277 % RGB image 278 % RGB圖像 第三維的維數為3 279 iptcheckinput(img, {'double' 'uint8' 'uint16' 'int16' 'single'}, ... 280 {}, mfilename, 'RGB1', 1); 281 imageType = 'truecolor'; 282 283 elseif (numel(lowhigh_in) == 2 && numel(lowhigh_out) == 2) || ... 284 size(img,2) ~= 3 285 % Assuming that a user passed in an intensity image if lowhigh_in and 286 % lowhigh_out are 2-element vectors, e.g., imadjust(3 column image, 287 % [1;2], [2;3]). 288 % 輸入圖像矩陣維數中列數不為3 289 iptcheckinput(img, {'double' 'uint8' 'uint16' 'int16' 'single'}, ... 290 {'2d'}, mfilename, 'I', 1); 291 imageType = 'intensity'; 292 293 else 294 %Colormap 295 iptcheckmap(img,mfilename,'MAP',1); 296 imageType = 'indexed'; 297 end 298 299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 300 function checkRange(range, imageType, argumentPosition, variableName) 301 302 if strcmp(imageType, 'intensity') 303 if numel(range) ~= 2 304 eid = sprintf('Images:%s:InputMustBe2ElVec',mfilename); 305 error(eid, ... 306 'Function %s expected its %s input argument, %s\n%s', ... 307 mfilename, iptnum2ordinal(argumentPosition), variableName, ... 308 'to be a two-element vector.'); 309 end 310 else 311 if ~(numel(range) == 2 || isequal(size(range), [2 3])) 312 eid = sprintf('Images:%s:InputMustBe2ElVecOr2by3Matrix',mfilename); 313 error(eid, ... 314 'Function %s expected its %s input argument, %s\n%s', ... 315 mfilename, iptnum2ordinal(argumentPosition), variableName, ... 316 'to be a two-element vector or a 2-by-3 matrix.'); 317 end 318 end 319 320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 321 function [rangeMin rangeMax] = splitRange(range, imageType) 322 323 if numel(range) == 2 324 if strcmp(imageType, 'intensity') 325 rangeMin = range(1); 326 rangeMax = range(2); 327 else 328 % Create triples for RGB image or Colormap 329 rangeMin = range(1) * ones(1,3); 330 rangeMax = range(2) * ones(1,3); 331 end 332 else 333 % range is a 2 by 3 array 334 rangeMin = range(1,:); 335 rangeMax = range(2,:); 336 end 337 338 339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 340 function validateLowHigh(lowIn,highIn,lowOut,highOut) 341 342 if any(lowIn >= highIn) 343 eid = sprintf('Images:%s:lowMustBeSmallerThanHigh',mfilename); 344 error(eid, '%s: LOW_IN must be less than HIGH_IN.',... 345 upper(mfilename)); 346 end 347 348 if isInvalidRange(lowIn) || isInvalidRange(highIn) ... 349 || isInvalidRange(lowOut) || isInvalidRange(highOut) 350 eid = sprintf('Images:%s:parametersAreOutOfRange',mfilename); 351 error(eid, '%s: LOW_IN, HIGH_IN, LOW_OUT and HIGH_OUT %s',... 352 upper(mfilename), 'must be in the range [0.0, 1.0].'); 353 end 354 355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 356 function isInvalid = isInvalidRange(range) 357 358 isInvalid = min(range) < 0 || max(range) > 1; 359 360 361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 362 function gamma = validateGamma(gamma,image_type) 363 364 if strcmp(image_type,'intensity') 365 iptcheckinput(gamma,{'double'},{'scalar', 'nonnegative'}, ... 366 mfilename, 'GAMMA', 4) 367 else 368 iptcheckinput(gamma,{'double'},{'nonnegative','2d'},... 369 mfilename, 'GAMMA', 4) 370 if numel(gamma) == 1, 371 gamma = gamma*ones(1,3); 372 end 373 end