├── utils └── Saturate.m ├── SIHR.m ├── Tan2005 ├── zResetLabels.m ├── zHighlightRemoval.m ├── zSpecular2Diffuse.m ├── zSpecularFreeImage.m ├── zRemoveHighlights.m ├── README.md ├── zInit.m ├── z.m └── zIteration.m ├── img ├── mit │ ├── apple.png │ ├── frog2.png │ ├── pear.png │ ├── pear_gt.png │ ├── teabag1.png │ ├── teabag2.png │ ├── apple_gt.png │ ├── frog2_gt.png │ ├── teabag1_gt.png │ └── teabag2_gt.png ├── mouse_cup.jpg ├── shen │ ├── cups.bmp │ ├── lady.bmp │ ├── wood.bmp │ ├── fruit.bmp │ ├── masks.bmp │ ├── rabbit.bmp │ ├── train.bmp │ ├── animals.bmp │ ├── cups_gt.bmp │ ├── fruit_gt.bmp │ ├── masks_gt.bmp │ ├── animals_gt.bmp │ └── watermelon.bmp └── tan │ ├── fish.ppm │ ├── head.ppm │ ├── pear.ppm │ ├── synth.ppm │ ├── toys.ppm │ └── circle.ppm ├── Shen2008 ├── Shen2008.m └── scp_spec_removal_web.m ├── Ramos2019 ├── OlderStuff │ ├── Show.m │ ├── KuwaharaFilter.m │ ├── Saturate.m │ ├── QualityMetrics.m │ ├── GetNewShaferRef.m │ ├── SoftClip.m │ ├── TSpace.m │ ├── NewShaferSpace.m │ ├── WpDec.m │ ├── Highpass.m │ ├── FourierApproach.m │ ├── Static.m │ ├── Demos.m │ ├── Interp.m │ ├── Tests.m │ ├── Mask.m │ ├── Ctds.m │ └── NewShen.m └── Ramos2019.m ├── Choudhury2005 ├── computeMagnitude.m ├── computeGradients.m ├── DemoTrilateralFilter.m ├── setAdaptiveNeighbourHood.m ├── trilateralFilter.m ├── license.txt ├── buildMinMaxImageStack.m ├── DetailBilateralFilter.m └── BilateralGradientFilter.m ├── Yang2010 ├── qx.m ├── README.md ├── qx_highlight_removal_bf.m ├── jbfilter2.m └── bfilter2.m ├── Yoon2006 ├── README.md ├── Yoon2006old.m └── Yoon2006.m ├── Akashi2015 ├── Akashi2015.m └── Akashi2015old.m ├── Shen2009 └── Shen2009.m ├── Yamamoto2017 ├── Yamamoto2017old.m └── Yamamoto2017.m └── README.md /utils/Saturate.m: -------------------------------------------------------------------------------- 1 | function Y = Saturate(X) 2 | Y = min(1,max(0,X)); 3 | end 4 | -------------------------------------------------------------------------------- /SIHR.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/SIHR.m -------------------------------------------------------------------------------- /Tan2005/zResetLabels.m: -------------------------------------------------------------------------------- 1 | function src = zResetLabels(src) 2 | src.i(src.i~=z.CAMERA_DARK) = 0; 3 | end 4 | 5 | -------------------------------------------------------------------------------- /img/mit/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/apple.png -------------------------------------------------------------------------------- /img/mit/frog2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/frog2.png -------------------------------------------------------------------------------- /img/mit/pear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/pear.png -------------------------------------------------------------------------------- /img/mouse_cup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mouse_cup.jpg -------------------------------------------------------------------------------- /img/shen/cups.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/cups.bmp -------------------------------------------------------------------------------- /img/shen/lady.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/lady.bmp -------------------------------------------------------------------------------- /img/shen/wood.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/wood.bmp -------------------------------------------------------------------------------- /img/tan/fish.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/tan/fish.ppm -------------------------------------------------------------------------------- /img/tan/head.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/tan/head.ppm -------------------------------------------------------------------------------- /img/tan/pear.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/tan/pear.ppm -------------------------------------------------------------------------------- /img/tan/synth.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/tan/synth.ppm -------------------------------------------------------------------------------- /img/tan/toys.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/tan/toys.ppm -------------------------------------------------------------------------------- /Shen2008/Shen2008.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/Shen2008/Shen2008.m -------------------------------------------------------------------------------- /img/mit/pear_gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/pear_gt.png -------------------------------------------------------------------------------- /img/mit/teabag1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/teabag1.png -------------------------------------------------------------------------------- /img/mit/teabag2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/teabag2.png -------------------------------------------------------------------------------- /img/shen/fruit.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/fruit.bmp -------------------------------------------------------------------------------- /img/shen/masks.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/masks.bmp -------------------------------------------------------------------------------- /img/shen/rabbit.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/rabbit.bmp -------------------------------------------------------------------------------- /img/shen/train.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/train.bmp -------------------------------------------------------------------------------- /img/tan/circle.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/tan/circle.ppm -------------------------------------------------------------------------------- /img/mit/apple_gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/apple_gt.png -------------------------------------------------------------------------------- /img/mit/frog2_gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/frog2_gt.png -------------------------------------------------------------------------------- /img/mit/teabag1_gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/teabag1_gt.png -------------------------------------------------------------------------------- /img/mit/teabag2_gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/mit/teabag2_gt.png -------------------------------------------------------------------------------- /img/shen/animals.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/animals.bmp -------------------------------------------------------------------------------- /img/shen/cups_gt.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/cups_gt.bmp -------------------------------------------------------------------------------- /img/shen/fruit_gt.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/fruit_gt.bmp -------------------------------------------------------------------------------- /img/shen/masks_gt.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/masks_gt.bmp -------------------------------------------------------------------------------- /img/shen/animals_gt.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/animals_gt.bmp -------------------------------------------------------------------------------- /img/shen/watermelon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/img/shen/watermelon.bmp -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Show.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/Ramos2019/OlderStuff/Show.m -------------------------------------------------------------------------------- /Shen2008/scp_spec_removal_web.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/Shen2008/scp_spec_removal_web.m -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/KuwaharaFilter.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Atif-Anwer/Specular-Highlight-Mitigation-Removal/HEAD/Ramos2019/OlderStuff/KuwaharaFilter.m -------------------------------------------------------------------------------- /Choudhury2005/computeMagnitude.m: -------------------------------------------------------------------------------- 1 | function gradientMagnitude = computeMagnitude(xGradient,yGradient) 2 | gradientMagnitude = sqrt(xGradient.^2 + yGradient.^2); 3 | end -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Saturate.m: -------------------------------------------------------------------------------- 1 | function Y = Saturate(X) 2 | %SATURATE Summary of this function goes here 3 | % Detailed explanation goes here 4 | Y = min(1,max(0,X)); 5 | end 6 | 7 | -------------------------------------------------------------------------------- /Choudhury2005/computeGradients.m: -------------------------------------------------------------------------------- 1 | function [xGradient,yGradient] = computeGradients(inputImage) 2 | xKernel = [-1,1]; 3 | yKernel = [-1;1]; 4 | xGradient = filter2(xKernel,inputImage,'same'); 5 | yGradient = filter2(yKernel,inputImage,'same'); 6 | end -------------------------------------------------------------------------------- /Tan2005/zHighlightRemoval.m: -------------------------------------------------------------------------------- 1 | function [img,sfi,diff] = zHighlightRemoval(fname) 2 | img.rgb = double(imread(fname)); 3 | img.rgb(end+1,1:end,:) = img.rgb(end,1:end,:); % pad post 4 | img.rgb(1:end,end+1,:) = img.rgb(1:end,end,:); 5 | img.i = zeros([size(img.rgb,1) size(img.rgb,2)],'uint8'); 6 | [sfi,diff] = zRemoveHighlights(img); 7 | img = img.rgb(1:end-1,1:end-1,:); 8 | end 9 | 10 | -------------------------------------------------------------------------------- /Choudhury2005/DemoTrilateralFilter.m: -------------------------------------------------------------------------------- 1 | load('durer'); 2 | inputImage = imresize(X,0.25); 3 | 4 | tic 5 | sigmaC = 8; 6 | epsilon = 0.1; 7 | outputImage = trilateralFilter(inputImage,sigmaC,epsilon); 8 | toc 9 | 10 | figure(1); 11 | subplot(1,2,1); imagesc(outputImage); title('Filtered'); colormap(gray); axis equal 12 | subplot(1,2,2); imagesc(inputImage); title('Original'); colormap(gray); axis equal -------------------------------------------------------------------------------- /Tan2005/zSpecular2Diffuse.m: -------------------------------------------------------------------------------- 1 | function [orgb,oi] = zSpecular2Diffuse(irgb,ii,maxChroma) 2 | c = z.MaxChroma(irgb); 3 | dI = (z.Max(irgb).*(3*c-1))./(c*(3*maxChroma-1)); 4 | sI = (z.Total(irgb)-dI)./3; 5 | nrgb = irgb-sI; 6 | if nrgb(:,:,1) <= 0 || nrgb(:,:,2) <= 0 || nrgb(:,:,3) <= 0 7 | orgb = irgb; 8 | oi = z.NOISE; 9 | return 10 | end 11 | orgb = nrgb; 12 | oi = ii; 13 | end 14 | 15 | -------------------------------------------------------------------------------- /Yang2010/qx.m: -------------------------------------------------------------------------------- 1 | %QX Class for bookkeeping constants 2 | % Edit qx for different values that affect the joint bilateral filtering. 3 | % Run qx_highlight_removal_bf for Yang's method. 4 | classdef qx 5 | properties (Constant) 6 | THR = 0.03 7 | SIGMAS = 3.0 8 | SIGMAR = 0.1 9 | SZ = 2*ceil(2*qx.SIGMAS)+1 10 | TOL = 1e-4; 11 | end 12 | end 13 | 14 | -------------------------------------------------------------------------------- /Tan2005/zSpecularFreeImage.m: -------------------------------------------------------------------------------- 1 | function [src,sfi] = zSpecularFreeImage(src) 2 | Lambda = 0.6; 3 | camDark = 20; 4 | r = src.rgb(:,:,1); g = src.rgb(:,:,2); b = src.rgb(:,:,3); 5 | src.i(intersect(intersect(find(r= 0 10 | src = zIteration(src,sfi,epsilon); 11 | % 12 | waitbar(1-2*epsilon,f) % disp(['epsilon = ' num2str(epsilon)]) 13 | % 14 | epsilon = epsilon - step; 15 | end 16 | % 17 | close(f) 18 | % 19 | sfi = sfi.rgb(1:end-1,1:end-1,:); 20 | diff = src.rgb(1:end-1,1:end-1,:); 21 | end 22 | 23 | -------------------------------------------------------------------------------- /Tan2005/README.md: -------------------------------------------------------------------------------- 1 | ## About 2 | 3 | A naïve MATLAB port of [1]. 4 | 5 | I welcome and encourage modifications upon validation. 6 | 7 | The method is more properly detailed in [2]. 8 | 9 | ## References 10 | 11 | 1. Specular Highlight Removal From A Single Image, PAMI 2005. Code: [highlight.zip](http://tanrobby.github.io/code/highlight.zip); 12 | 13 | 2. R. T. Tan and K. Ikeuchi, “Separating reflection components of textured surfaces using a single image,” IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 27, no. 2, pp. 178–193, Feb. 2005 [Online]. Available: http://dx.doi.org/10.1109/TPAMI.2005.36. 14 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/SoftClip.m: -------------------------------------------------------------------------------- 1 | function imSc = SoftClip(imDbl,k) 2 | %SOFTCLIP Soft clip function (tanh-based) 3 | % imSc = SoftClip(imDbl,k) outputs soft-clipped image imSc. 4 | % 5 | % imDbl must be double-valued and be on the (0;1) interval. 6 | % 7 | % k corresponds to how affected the image will be. It is optional and 8 | % must be a positive integer (0;Inf]. 9 | % 10 | % Its default value is 3 - corresponds to a soft clip of: in=1, out=0.94. 11 | % 12 | % k = 0 outputs tanh(imDbl). 13 | if ~exist('k','var') || isempty(k) 14 | k = 3; 15 | end 16 | imDbl = imDbl + 0.5*rand(size(imDbl))/255; % quantization step dither 17 | imSc = (tanh(imDbl) + k*imDbl)/(k+1); 18 | end 19 | 20 | -------------------------------------------------------------------------------- /Choudhury2005/setAdaptiveNeighbourHood.m: -------------------------------------------------------------------------------- 1 | function adaptiveNeighbourhood = setAdaptiveNeighbourHood(... 2 | gradientMagnitude,sigmaR,maxLevel) 3 | 4 | adaptiveNeighbourhood = zeros(size(gradientMagnitude)); 5 | [minStack,maxStack] = buildMinMaxImageStack(gradientMagnitude,maxLevel); 6 | 7 | for row = 1:size(gradientMagnitude,1) 8 | for col = 1:size(gradientMagnitude,2) 9 | upperThreshold = gradientMagnitude(row,col) + sigmaR; 10 | lowerThreshold = gradientMagnitude(row,col) - sigmaR; 11 | for lev = 1:maxLevel 12 | minImg = minStack(:,:,lev); 13 | maxImg = maxStack(:,:,lev); 14 | if maxImg(row,col)>upperThreshold || minImg(row,col)=1/3-qx.TOL & sigmaMin<=1/3+qx.TOL; 15 | sIdx3 = repmat(sIdx,[1 1 3]); 16 | 17 | lambda = ones(size(src))/3; 18 | lambda(~sIdx3) = (sigma(~sIdx3)-sigmaMin3(~sIdx3))./... 19 | (3*(lambda(~sIdx3)-sigmaMin3(~sIdx3))); 20 | lambdaMax = max(lambda,[],3); 21 | 22 | while true 23 | sigmaMaxF = im2double(bfilter2(sigmaMax,lambdaMax,qx.SZ,qx.SIGMAS,qx.SIGMAR)); 24 | if nnz(sigmaMaxF-sigmaMax>qx.THR) == 0 25 | break 26 | end 27 | sigmaMax = max(sigmaMax,sigmaMaxF); 28 | end 29 | 30 | zIdx = (sigmaMax>=1/3-qx.TOL) & (sigmaMax<=1/3+qx.TOL); 31 | 32 | srcMax = max(src,[],3); 33 | 34 | sfi = zeros([size(src,1) size(src,2)]); 35 | sfi(~zIdx) = (srcMax(~zIdx)-sigmaMax(~zIdx).*total(~zIdx))./(1-3*sigmaMax(~zIdx)); 36 | sfi3 = repmat(sfi,[1 1 3]); 37 | 38 | mIdx = sigmaMax<=1/3+qx.TOL; 39 | mIdx3 = repmat(mIdx,[1 1 3]); 40 | 41 | dst = src; 42 | dst(~mIdx3) = src(~mIdx3)-sfi3(~mIdx3); 43 | end 44 | 45 | -------------------------------------------------------------------------------- /Tan2005/zInit.m: -------------------------------------------------------------------------------- 1 | function [src,count] = zInit(src,sfi,epsilon) 2 | count = 0; 3 | nY = size(src.rgb,1); 4 | nX = size(src.rgb,2); 5 | dlog_src_x = log(abs(z.Total(src.rgb(1:nY-1,2:nX ,:))-... 6 | z.Total(src.rgb(1:nY-1,1:nX-1,:)))); 7 | dlog_src_y = log(abs(z.Total(src.rgb(2:nY ,1:nX-1,:))-... 8 | z.Total(src.rgb(1:nY-1,1:nX-1,:)))); 9 | dlog_sfi_x = log(abs(z.Total(sfi.rgb(1:nY-1,2:nX ,:))-... 10 | z.Total(sfi.rgb(1:nY-1,1:nX-1,:)))); 11 | dlog_sfi_y = log(abs(z.Total(sfi.rgb(2:nY ,1:nX-1,:))-... 12 | z.Total(sfi.rgb(1:nY-1,1:nX-1,:)))); 13 | dlogx = abs(dlog_src_x-dlog_sfi_x); 14 | dlogy = abs(dlog_src_y-dlog_sfi_y); 15 | for iY = 1:nY-1 16 | for iX = 1:nX-1 17 | switch src.i(iY,iX) 18 | case z.BOUNDARY 19 | continue 20 | case z.NOISE 21 | continue 22 | case z.CAMERA_DARK 23 | continue 24 | end 25 | if dlogx(iY,iX) > epsilon 26 | src.i(iY,iX) = z.SPECULARX; 27 | count = count + 1; 28 | continue 29 | end 30 | if dlogy(iY,iX) > epsilon 31 | src.i(iY,iX) = z.SPECULARY; 32 | count = count + 1; 33 | continue 34 | end 35 | src.i(iY,iX) = z.DIFFUSE; 36 | end 37 | end 38 | end 39 | 40 | -------------------------------------------------------------------------------- /Choudhury2005/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Pekka Astola 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | 26 | http://freesourcecode.net/matlabprojects/62035/two-dimensional-trilateral-filter-in-matlab#.XJMdAIrVK9I -------------------------------------------------------------------------------- /Akashi2015/Akashi2015.m: -------------------------------------------------------------------------------- 1 | V = double(imread('synth.ppm')); 2 | [nRow,nCol,nCh] = size(V); 3 | M = 3; % = number of color channels 4 | N = nRow*nCol; % = number of pixels 5 | R = 6; % = number of color clusters -1 6 | V = reshape(V,[N M])'; 7 | i_s = [1 1 1]'/sqrt(3); 8 | H = 254*rand(R,N) + 1; 9 | W_d = 254*rand(3,R-1) + 1; 10 | W_d = W_d./vecnorm(W_d,2,1); % normc(W_d); % normalize(W_d,1,'norm'); 11 | W = [i_s W_d]; 12 | A = ones(M); 13 | lambda = 3; 14 | eps = exp(-15); 15 | F_t_1 = Inf; 16 | iter = uint16(0); 17 | maxIter = uint16(10e3); % change for later convergence (takes way longer) 18 | % tic 19 | while true 20 | W_bar = W./vecnorm(W,2,1); % normc(W); % normalize(W,1,'norm'); 21 | H = H.*((W_bar')*V)./... 22 | ((W_bar')*W_bar*H + lambda); 23 | H_d = H(2:end,:); 24 | Vl = max(0,V - i_s*H(1,:)); 25 | % W_d = W(:,2:end); % not sure 26 | W_d_bar = W_bar(:,2:end); 27 | W_d = W_d_bar.*(Vl*(H_d') + W_d_bar.*(A*W_d_bar*H_d*(H_d')))./... 28 | (W_d_bar*H_d*(H_d') + W_d_bar.*(A*Vl*(H_d'))); 29 | W = [i_s W_d]; 30 | F_t = 0.5*norm((V-W*H),'fro') + lambda*sum(H,'all'); 31 | if abs(F_t - F_t_1) < eps*abs(F_t) || iter >= maxIter 32 | break 33 | end 34 | F_t_1 = F_t; 35 | iter = iter + 1; 36 | end 37 | % toc 38 | W_d = W(:,2:end); 39 | h_s = H(1,:); 40 | H_d = H(2:end,:); 41 | I_s = i_s*h_s; 42 | I_d = W_d*H_d; 43 | I_s = reshape(full(I_s)',[nRow,nCol,nCh]); 44 | I_d = reshape(full(I_d)',[nRow,nCol,nCh]); 45 | 46 | figure(1), imshow(I_s/255) 47 | figure(2), imshow(I_d/255) 48 | -------------------------------------------------------------------------------- /Choudhury2005/buildMinMaxImageStack.m: -------------------------------------------------------------------------------- 1 | function [minStack,maxStack] = buildMinMaxImageStack(gradientMagnitude,maxLevel) 2 | 3 | minStack = zeros(... 4 | size(gradientMagnitude,1),... 5 | size(gradientMagnitude,2),... 6 | maxLevel); 7 | maxStack = minStack; 8 | minImg1 = minStack(:,:,1); 9 | maxImg1 = maxStack(:,:,1); 10 | 11 | for row = 1:size(minStack,1) 12 | for col = 1:size(minStack,2) 13 | outMin = 1E12; 14 | outMax = -1E12; 15 | for n = max(row-1,1):min(row+2,size(minStack,1)) 16 | for m = max(col-1,1):min(col+2,size(minStack,2)) 17 | outMin = min(gradientMagnitude(n,m),outMin); 18 | outMax = max(gradientMagnitude(n,m),outMax); 19 | end 20 | end 21 | minImg1(row,col) = outMin; 22 | maxImg1(row,col) = outMax; 23 | end 24 | end 25 | 26 | for ii = 2:size(minStack,3) 27 | minImg1 = minStack(:,:,ii-1); 28 | maxImg1 = maxStack(:,:,ii-1); 29 | 30 | minImg2 = minStack(:,:,ii); 31 | maxImg2 = maxStack(:,:,ii); 32 | 33 | for row = 1:size(minStack,1) 34 | for col = 1:size(minStack,2) 35 | outMin = 1E12; 36 | outMax = -1E12; 37 | for n = max(row-1,1):min(row+2,size(minStack,1)) 38 | for m = max(col-1,1):min(col+2,size(minStack,2)) 39 | outMin = min(minImg1(n,m),outMin); 40 | outMax = max(maxImg1(n,m),outMax); 41 | end 42 | end 43 | minImg2(row,col) = outMin; 44 | maxImg2(row,col) = outMax; 45 | end 46 | end 47 | end 48 | 49 | end -------------------------------------------------------------------------------- /Akashi2015/Akashi2015old.m: -------------------------------------------------------------------------------- 1 | V = double(imread('watermelon.bmp')); 2 | [nRow,nCol,nCh] = size(V); 3 | M = 3; % = number of color channels 4 | N = nRow*nCol; % = number of pixels 5 | R = 6; % = number of color clusters -1 6 | V = reshape(V,[N M])'; 7 | i_s = [1 1 1]'/sqrt(3); 8 | H = 254*rand(R,N) + 1; 9 | W_d = 254*rand(3,R-1) + 1; 10 | W_d = normalize(W_d,1,'norm'); 11 | W = [i_s W_d]; 12 | A = ones(M); 13 | lambda = 3; 14 | eps = exp(-15); 15 | F_t_1 = Inf; 16 | count = uint16(0); 17 | % tic 18 | while true 19 | W_bar = normalize(W,1,'norm'); 20 | H = H.*((W_bar')*V)./... 21 | ((W_bar')*W_bar*H + lambda); 22 | H_d = H(2:end,:); 23 | Vl = max(0,V - i_s*H(1,:)); 24 | % W_d = W(:,2:end); % ??????????? 25 | W_d_bar = W_bar(:,2:end); 26 | W_d = W_d_bar.*(Vl*(H_d') + W_d_bar.*(A*W_d_bar*H_d*(H_d')))./... 27 | (W_d_bar*H_d*(H_d') + W_d_bar.*(A*Vl*(H_d'))); 28 | W = [i_s W_d]; 29 | F_t = 0.5*norm((V-W*H),'fro') + lambda*sum(H,'all'); 30 | if abs(F_t - F_t_1) < eps*abs(F_t) || count >= 10000 31 | break 32 | end 33 | F_t_1 = F_t; 34 | count = count + 1; 35 | end 36 | % toc 37 | W_d = W(:,2:end); 38 | h_s = H(1,:); 39 | H_d = H(2:end,:); 40 | I_s = i_s*h_s; 41 | I_d = W_d*H_d; 42 | I_s = reshape(full(I_s)',[nRow,nCol,nCh]); 43 | I_d = reshape(full(I_d)',[nRow,nCol,nCh]); 44 | figure(1), imshow(I_s/255) 45 | figure(2), imshow(I_d/255) 46 | 47 | 48 | % On (3), normalize is a bare MATLAB function introduced in R2018a. You could replace it for normc, which is not a bare MATLAB function but was introduced earlier (R2006a). 49 | % Or divide W_d by the norm (R2006a) of W_d taken along the columns. 50 | -------------------------------------------------------------------------------- /Shen2009/Shen2009.m: -------------------------------------------------------------------------------- 1 | % Code for the following paper: 2 | % H. L. Shen, H. G. Zhang, S. J. Shao, and J. H. Xin, 3 | % Simple and Efficient Method for Specularity Removal in an Image, 4 | 5 | clear; close all; 6 | 7 | threshold_chroma = 0.03; 8 | nu = 0.5; 9 | 10 | I = imread('images\4k.bmp'); 11 | I = double(I); 12 | [height, width, dim] = size(I); 13 | 14 | I3c = reshape(I, height*width, 3); 15 | tic; 16 | % calculate specular-free image 17 | Imin = min(I3c, [], 2); 18 | Imax = max(I3c, [], 2); 19 | Ithresh = mean(Imin) + nu * std(Imin); 20 | Iss = I3c - repmat(Imin, 1, 3) .* (Imin > Ithresh) + Ithresh * (Imin > Ithresh); 21 | 22 | % calculate specular component 23 | IBeta = (Imin - Ithresh) .* (Imin > Ithresh) + 0; 24 | 25 | % estimate largest region of highlight 26 | IHighlight = reshape(IBeta, height, width, 1); 27 | IHighlight = mat2gray(IHighlight); 28 | IHighlight = im2bw(IHighlight, 0.1); 29 | IDominantRegion = bwareafilt(IHighlight, 1, 'largest'); 30 | 31 | % dilate largest region by 5 pixels to obtain its surrounding region 32 | se = strel('square',5); 33 | ISurroundingRegion = imdilate(IDominantRegion, se); 34 | ISurroundingRegion = logical(imabsdiff(ISurroundingRegion, IDominantRegion)); 35 | 36 | % Solve least squares problem 37 | Vdom = mean(I3c(IDominantRegion, :)); 38 | Vsur = mean(I3c(ISurroundingRegion, :)); 39 | Betadom = mean(IBeta(IDominantRegion, :)); 40 | Betasur = mean(IBeta(ISurroundingRegion, :)); 41 | k = (Vsur - Vdom)/(Betasur - Betadom); 42 | 43 | % Estimate diffuse and specular components 44 | Idf = I3c - min(k) * IBeta; 45 | Isp = I3c - Idf; 46 | 47 | %figure; imshow(uint8(reshape(I3c, height, width, 3))); title('original'); 48 | %figure; imshow(uint8(reshape(Idf, height, width, 3))); title('diffuse component'); 49 | %figure; imshow(uint8(reshape(Isp, height, width, 3))); title('specular component'); 50 | 51 | 52 | %imwrite(uint8(reshape(Idf, height, width, 3)), 'comp_df.bmp', 'bmp'); 53 | %imwrite(uint8(reshape(Isp, height, width, 3)), 'comp_sp.bmp', 'bmp'); 54 | toc; 55 | 56 | -------------------------------------------------------------------------------- /Tan2005/z.m: -------------------------------------------------------------------------------- 1 | classdef z 2 | properties (Constant) 3 | SPECULARX = uint8(10) 4 | SPECULARY = uint8(11) 5 | DIFFUSE = uint8(12) 6 | BOUNDARY = uint8(13) 7 | NOISE = uint8(14) 8 | CAMERA_DARK = uint8(15) 9 | end 10 | methods(Static) 11 | function [src,sfi,diff] = main(fname) 12 | [src,sfi,diff] = zHighlightRemoval(fname); 13 | src = src/255; 14 | sfi = sfi/255; 15 | diff = diff/255; 16 | end 17 | function c = Chroma_r(rgb) 18 | r = rgb(:,:,1); 19 | t = z.Total(rgb); 20 | c = zeros(size(r)); 21 | if any(t(:)) 22 | c(t~=0) = r(t~=0)./t(t~=0); 23 | end 24 | c(t==0) = 0; 25 | end 26 | function c = Chroma_g(rgb) 27 | g = rgb(:,:,2); 28 | t = z.Total(rgb); 29 | c = zeros(size(g)); 30 | if any(t(:)) 31 | c(t~=0) = g(t~=0)./t(t~=0); 32 | end 33 | c(t==0) = 0; 34 | end 35 | function c = Chroma_b(rgb) 36 | b = rgb(:,:,3); 37 | t = z.Total(rgb); 38 | c = zeros(size(b)); 39 | if any(t(:)) 40 | c(t~=0) = b(t~=0)./t(t~=0); 41 | end 42 | c(t==0) = 0; 43 | end 44 | function m = Max(rgb) 45 | m = max(rgb,[],3); 46 | end 47 | function c = MaxChroma(rgb) 48 | m = z.Max(rgb); 49 | t = z.Total(rgb); 50 | c = zeros(size(m)); 51 | if any(t(:)) 52 | c(t~=0) = m(t~=0)./t(t~=0); 53 | end 54 | c(t==0) = 0; 55 | end 56 | function m = Min(rgb) 57 | m = min(rgb,[],3); 58 | end 59 | function t = Total(rgb) 60 | t = sum(rgb,3); 61 | end 62 | end 63 | end 64 | 65 | -------------------------------------------------------------------------------- /Choudhury2005/DetailBilateralFilter.m: -------------------------------------------------------------------------------- 1 | function outputImage = DetailBilateralFilter(inputImage,adaptiveRegion,... 2 | xGradientSmooth,yGradientSmooth,sigmaC,sigmaR,maxDomainSize,epsilon) 3 | 4 | outputImage = zeros(size(inputImage)); 5 | domainConst = -2*sigmaC*sigmaC; 6 | rangeConst = -2*sigmaR*sigmaR; 7 | 8 | domainWeight = zeros(maxDomainSize,maxDomainSize); 9 | 10 | for row = 1:size(domainWeight,1) 11 | for col = 1:size(domainWeight,2) 12 | diff_ = row*row+col*col; 13 | domainWeight(row,col ) = exp(diff_/domainConst); 14 | end 15 | end 16 | 17 | for row = 1:size(inputImage,1) 18 | for col = 1:size(inputImage,2) 19 | normFactor = 0; 20 | tmp = 0; 21 | halfSize = min(adaptiveRegion(row,col),maxDomainSize); 22 | coeffA = xGradientSmooth(row,col); 23 | coeffB = yGradientSmooth(row,col); 24 | coeffC = inputImage(row,col); 25 | for n = -halfSize:halfSize 26 | for m = -halfSize:halfSize 27 | if (n && m) 28 | dWeight = domainWeight(abs(n),abs(m)); 29 | if dWeight < epsilon 30 | continue 31 | end 32 | localX = col + m; 33 | if localX < 1 34 | continue 35 | end 36 | if localX >= size(inputImage,2)+1 37 | continue 38 | end 39 | localY = row +n; 40 | if localY < 1 41 | continue 42 | end 43 | if localY >= size(inputImage,1)+1 44 | continue 45 | end 46 | detail = inputImage(localY,localX) - coeffA*m - ... 47 | coeffB*n - coeffC; 48 | rangeWeight = exp(detail^2 / rangeConst); 49 | tmp = tmp+detail*dWeight*rangeWeight; 50 | normFactor = normFactor + dWeight*rangeWeight; 51 | end 52 | end 53 | end 54 | outputImage(row,col) = tmp/normFactor + coeffC; 55 | end 56 | end 57 | 58 | end -------------------------------------------------------------------------------- /Yoon2006/Yoon2006old.m: -------------------------------------------------------------------------------- 1 | %% Import image to workspace 2 | I = im2double(imread('watermelon.bmp')); 3 | % figure(1), imshow(I) 4 | %% Create specular-free two-band image 5 | Isf = I - min(I,[],3); 6 | % figure(2), imshow(Isf) 7 | %% Get its chroma 8 | c = getChroma(Isf); 9 | cr = c(:,:,1); 10 | cg = c(:,:,2); 11 | %% Dimensions 12 | [nRow,nCol,nCh] = size(I); 13 | %% Reshape to column vector (easier indexing) 14 | I_col = reshape(I,[nRow*nCol nCh]); 15 | Isf_col = reshape(Isf,[nRow*nCol nCh]); 16 | cr_col = reshape(cr,[nRow*nCol 1]); 17 | cg_col = reshape(cg,[nRow*nCol 1]); 18 | skip = false([nRow*nCol 1]); 19 | %% Chroma threshold values (color discontinuity) 20 | thR = 0.05; thG = 0.05; 21 | %% Iterates until only diffuse pixels are left 22 | count = uint8(0); 23 | iter = uint8(0); 24 | while true 25 | for x1 = 1:nRow*nCol-1 26 | x2 = x1 + 1; 27 | if skip(x1) 28 | continue 29 | elseif sum(Isf_col(x2),2) == 0 ||... 30 | sum(I_col(x2),2) == 0 ||... 31 | (abs(cr_col(x1)-cr_col(x2)) > thR &&... 32 | abs(cg_col(x1)-cg_col(x2)) > thG) 33 | skip(x1) = true; 34 | continue 35 | end 36 | % Get local r_{d+s} ratio and r_{d} 37 | rd = sum(Isf_col(x1),2)/sum(Isf_col(x2),2); 38 | rds = sum(I_col(x1),2)/sum(I_col(x2),2); 39 | % Compare ratios and decrease intensity 40 | if rds > rd 41 | m = sum(I_col(x1,2)) - rd*sum(I_col(x2,2)); 42 | if m < 1e-3 43 | continue 44 | end 45 | I_col(x1,:) = max(0,I_col(x1,:) - m/3); 46 | count = count + 1; 47 | elseif rds < rd 48 | m = sum(I_col(x2,2)) - sum(I_col(x1,2))/rd; 49 | if m < 1e-3 50 | continue 51 | end 52 | I_col(x2,:) = max(0,I_col(x2,:) - m/3); 53 | count = count + 1; 54 | end 55 | end 56 | if count == 0 || iter == 255 57 | break 58 | end 59 | count = 0; 60 | iter = iter + 1; 61 | end 62 | %% Display diffuse image 63 | Idiff = reshape(I_col,[nRow nCol nCh]); 64 | figure(3), imshow(Idiff) 65 | %% Helper function 66 | function cI = getChroma(I) 67 | sI = repmat(sum(I,3),[1 1 3]); 68 | val = sI<1e-3; 69 | cI = zeros(size(I)); 70 | cI(~val) = I(~val)./sI(~val); 71 | end 72 | 73 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/NewShaferSpace.m: -------------------------------------------------------------------------------- 1 | function [imT,T] = NewShaferSpace(imRef,imDbl,sel) 2 | %NEWSHAFERSPACE Modified Shafer-space transformation 3 | % [imT,T] = NewShaferSpace(imRef,imDbl,sel) returns transformed image imT 4 | % and the transformation matrix T used. 5 | % 6 | % Inputs imRef and imDbl must be double-valued RGB images. 7 | % 8 | % Argument sel = 'fwd' assures forward transform and sel = 'rev' reverse. 9 | % 10 | % If size(imRef) is [3 3], that is, a transformation matrix (e.g. T), 11 | % it'll be used instead of approximating a new space. 12 | % 13 | % For proper inversion, either imRef should stay the same between calls, 14 | % or argument T returned in forward transformation must be input. 15 | % 16 | % See also: pinv 17 | if isequal(size(imRef),[3 3]) 18 | T = imRef; 19 | else 20 | T = GetTransformationMatrix(imRef); 21 | end 22 | switch sel 23 | case 'fwd' 24 | r = imDbl(:,:,1); 25 | g = imDbl(:,:,2); 26 | b = imDbl(:,:,3); 27 | bod = T(1,1)*r + T(1,2)*g + T(1,3)*b; 28 | ill = T(2,1)*r + T(2,2)*g + T(2,3)*b; 29 | err = T(3,1)*r + T(3,2)*g + T(3,3)*b; 30 | imT = cat(3,bod,ill,err); 31 | case 'rev' 32 | bod = imDbl(:,:,1); 33 | ill = imDbl(:,:,2); 34 | err = imDbl(:,:,3); 35 | r = T(1,1)*bod + T(2,1)*ill + T(3,1)*err; 36 | g = T(1,2)*bod + T(2,2)*ill + T(3,2)*err; 37 | b = T(1,3)*bod + T(2,3)*ill + T(3,3)*err; 38 | imT = cat(3,r,g,b); 39 | otherwise 40 | imT = imDbl; 41 | end 42 | function T = GetTransformationMatrix(imRef) 43 | r = mean2(imRef(:,:,1)); 44 | g = mean2(imRef(:,:,2)); 45 | b = mean2(imRef(:,:,3)); 46 | % https://www.mathworks.com/matlabcentral/fileexchange/36353-planefit 47 | xx = [0 r 1]'; 48 | yy = [0 g 1]'; 49 | zz = [0 b 1]'; 50 | N = length(xx); 51 | O = ones(N,1); 52 | C = pinv([xx yy O],1e-3)*zz; 53 | % http://mathworld.wolfram.com/NormalVector.html 54 | nn = [C(1) C(2) -1]; 55 | nn = nn/norm(nn); 56 | % 57 | vv = [r g b]; 58 | vv = vv/norm(vv); 59 | % 60 | ww = cross(nn,vv); 61 | ww = ww/norm(ww); 62 | % 63 | T = [vv; 64 | ww; 65 | nn]; 66 | end 67 | end 68 | 69 | -------------------------------------------------------------------------------- /Choudhury2005/BilateralGradientFilter.m: -------------------------------------------------------------------------------- 1 | function [xGradientSmooth,yGradientSmooth] = BilateralGradientFilter(... 2 | xGradient,yGradient,gradientMagnitude,sigmaC,sigmaR,epsilon) 3 | 4 | xGradientSmooth = zeros(size(xGradient)); 5 | yGradientSmooth = xGradientSmooth; 6 | domainConst = -2*sigmaC*sigmaC; 7 | rangeConst = -2*sigmaR*sigmaR; 8 | halfSize = ceil(sigmaC/2); 9 | domainWeight = zeros(halfSize,halfSize); 10 | 11 | for row = 1:size(domainWeight,1) 12 | for col = 1:size(domainWeight,2) 13 | diff_ = col*col+row*row; 14 | domainWeight(row,col) = exp(diff_/domainConst); 15 | end 16 | end 17 | 18 | for row = 1:size(gradientMagnitude,1) 19 | for col = 1:size(gradientMagnitude,2) 20 | normFactor = 0; 21 | tmpX = 0; 22 | tmpY = 0; 23 | g2 = gradientMagnitude(row,col); 24 | for n = -halfSize:halfSize 25 | for m = -halfSize:halfSize 26 | if (n && m) 27 | dWeight = domainWeight(abs(n),abs(m)); 28 | if dWeight < epsilon 29 | continue 30 | end 31 | localX = col + m; 32 | if localX < 1 33 | continue 34 | end 35 | if localX >= size(gradientMagnitude,2)+1 36 | continue 37 | end 38 | localY = row +n; 39 | if localY < 1 40 | continue 41 | end 42 | if localY >= size(gradientMagnitude,1)+1 43 | continue 44 | end 45 | g1 = gradientMagnitude(localY,localX); 46 | gradDiffSq = (g1-g2)^2; 47 | rangeWeight = exp(gradDiffSq/rangeConst); 48 | if rangeWeight < epsilon 49 | continue 50 | end 51 | tmpX = tmpX + xGradient(localY,localX)*dWeight*rangeWeight; 52 | tmpY = tmpY + yGradient(localY,localX)*dWeight*rangeWeight; 53 | normFactor = normFactor + dWeight*rangeWeight; 54 | end 55 | end 56 | end 57 | xGradientSmooth(row,col) = tmpX/normFactor; 58 | yGradientSmooth(row,col) = tmpY/normFactor; 59 | end 60 | end 61 | 62 | end -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/WpDec.m: -------------------------------------------------------------------------------- 1 | % waveletAnalyzer 2 | src = imresize(imread('img\fish.ppm'),[256 NaN],'lanczos3'); 3 | dst = src; 4 | count = 0; 5 | while true 6 | count = count + 1; 7 | if count >= 64 % ~32, count has to be approximately the highlight dynamic range 8 | break 9 | end 10 | t = wpdec2(dst,1,'bior3.1','log energy'); 11 | [aR,aG,aB] = imsplit(read(t,'data',1)); 12 | nNode = [2 3 4]; 13 | for iNode = nNode 14 | [cR,cG,cB] = imsplit(read(t,'data',iNode)); 15 | % 16 | muR = mean2(cR(:)); 17 | muG = mean2(cG(:)); 18 | muB = mean2(cB(:)); 19 | % 20 | sigmaR = std(cR(:)); 21 | sigmaG = std(cG(:)); 22 | sigmaB = std(cB(:)); 23 | % 24 | v = 2; % v could be a function of # of counts 25 | % % thr could also be denoise-related e.g. Birge-Massart 26 | thrR = muR + v*sigmaR; 27 | thrG = muG + v*sigmaG; 28 | thrB = muB + v*sigmaB; 29 | % 30 | idxR = abs(cR) > thrR; 31 | idxG = abs(cG) > thrG; 32 | idxB = abs(cB) > thrB; 33 | % 34 | idxAndRGB = idxR & idxG & idxB; 35 | if nnz(idxAndRGB) == 0 36 | break 37 | end 38 | idxOrRGB = idxR | idxG | idxB; 39 | % 40 | nR = cR; 41 | nG = cG; 42 | nB = cB; 43 | % 44 | nR(idxOrRGB) = 0.976470588235294*nR(idxOrRGB); % 249/255 45 | nG(idxOrRGB) = 0.976470588235294*nG(idxOrRGB); 46 | nB(idxOrRGB) = 0.976470588235294*nB(idxOrRGB); 47 | % 48 | ncfs = cat(3,nR,nG,nB); 49 | t = write(t,'data',iNode,ncfs); 50 | % 51 | aR(idxAndRGB) = 0.992156862745098*aR(idxAndRGB); % 253/255 52 | aG(idxAndRGB) = 0.992156862745098*aG(idxAndRGB); 53 | aB(idxAndRGB) = 0.992156862745098*aB(idxAndRGB); 54 | % 55 | idxNeqRGB = ~idxAndRGB & idxOrRGB; 56 | % 57 | aM = min(min(aR,aG),aB); 58 | % 59 | aR(idxNeqRGB) = aR(idxNeqRGB) - fix(0.007843137254902*aM(idxNeqRGB)); % 2/255 60 | aG(idxNeqRGB) = aG(idxNeqRGB) - fix(0.007843137254902*aM(idxNeqRGB)); 61 | aB(idxNeqRGB) = aB(idxNeqRGB) - fix(0.007843137254902*aM(idxNeqRGB)); 62 | end 63 | if nnz(idxAndRGB) == 0 64 | break 65 | end 66 | acfs = cat(3,aR,aG,aB); 67 | t = write(t,'data',1,acfs); 68 | dst = wprec2(t); 69 | end 70 | imshowpair(src,dst,'montage') -------------------------------------------------------------------------------- /Yoon2006/Yoon2006.m: -------------------------------------------------------------------------------- 1 | %% Import image to workspace 2 | I = im2double(imread('synth.ppm')); 3 | % figure(1), imshow(I) 4 | %% Create specular-free two-band image 5 | Isf = I - min(I,[],3); 6 | % figure(2), imshow(Isf) 7 | %% Get its chroma 8 | den = repmat(sum(Isf,3),[1 1 3]); 9 | zero = den==0; 10 | c = zeros(size(Isf)); 11 | c(~zero) = Isf(~zero)./den(~zero); 12 | clear den zero 13 | %% 14 | % c = getChroma(Isf); 15 | cr = c(:,:,1); 16 | cg = c(:,:,2); 17 | %% Dimensions 18 | [nRow,nCol,nCh] = size(I); 19 | %% Reshape to column vector (easier indexing) 20 | I_col = reshape(I,[nRow*nCol nCh]); 21 | Isf_col = reshape(Isf,[nRow*nCol nCh]); 22 | cr_col = reshape(cr,[nRow*nCol 1]); 23 | cg_col = reshape(cg,[nRow*nCol 1]); 24 | skip = false([nRow*nCol 1]); 25 | %% Chroma threshold values (color discontinuity) 26 | thR = 0.05; thG = 0.05; 27 | %% Iterates until only diffuse pixels are left 28 | count = uint16(0); 29 | iter = uint16(0); 30 | while true 31 | for x1 = 1:nRow*nCol-1 32 | x2 = x1 + 1; 33 | if skip(x1) 34 | continue 35 | elseif sum(Isf_col(x2),2) == 0 ||... 36 | sum(I_col(x2),2) == 0 ||... 37 | (abs(cr_col(x1)-cr_col(x2)) > thR &&... 38 | abs(cg_col(x1)-cg_col(x2)) > thG) 39 | skip(x1) = true; 40 | continue 41 | end 42 | % Get local r_{d+s} ratio and r_{d} 43 | rd = sum(Isf_col(x1),2)/sum(Isf_col(x2),2); 44 | rds = sum(I_col(x1),2)/sum(I_col(x2),2); 45 | % Compare ratios and decrease intensity 46 | if rds > rd 47 | m = sum(I_col(x1,2)) - rd*sum(I_col(x2,2)); 48 | if m < 1e-3 49 | continue 50 | end 51 | I_col(x1,:) = max(0,I_col(x1,:) - m/3); 52 | count = count + 1; 53 | elseif rds < rd 54 | m = sum(I_col(x2,2)) - sum(I_col(x1,2))/rd; 55 | if m < 1e-3 56 | continue 57 | end 58 | I_col(x2,:) = max(0,I_col(x2,:) - m/3); 59 | count = count + 1; 60 | end 61 | end 62 | if count == 0 || iter == 1000 63 | break 64 | end 65 | count = 0; 66 | iter = iter + 1; 67 | end 68 | %% Display diffuse image 69 | Idiff = reshape(I_col,[nRow nCol nCh]); 70 | figure(3), imshow(Idiff) 71 | 72 | % function cI = getChroma(I) 73 | % sI = repmat(sum(I,3),[1 1 3]); 74 | % zeroI = sI==0; 75 | % cI = zeros(size(I)); 76 | % cI(~zeroI) = I(~zeroI)./sI(~zeroI); 77 | % end 78 | -------------------------------------------------------------------------------- /Yamamoto2017/Yamamoto2017old.m: -------------------------------------------------------------------------------- 1 | %% Import image to workspace 2 | i_input = im2double(imread('watermelon.bmp')); 3 | [nRow,nCol,nCh] = size(i_input); 4 | %% i = i_d + i_s 5 | i_d = qx_highlight_removal_bf(i_input); % or another highlight removal method 6 | i_s = min(1,max(0,(i_input - i_d))); 7 | %% Iteration constraints 8 | count = uint8(0); 9 | e = 0.2; 10 | %% While loop 11 | while true 12 | %% (cont.) 13 | k = 10; 14 | h = fspecial('average',3); 15 | i_input_bf = imfilter(i_input,h,'symmetric'); 16 | i_d_bf = imfilter(i_d, h,'symmetric'); 17 | i_s_bf = imfilter(i_s, h,'symmetric'); 18 | %% (cont.) 19 | i_input_um = Saturate(i_input + k*Saturate(i_input - i_input_bf)); 20 | i_d_um = Saturate(i_d + k*Saturate(i_d - i_d_bf )); 21 | i_s_um = Saturate(i_s + k*Saturate(i_s - i_s_bf )); 22 | %% (cont.) 23 | i_combined_um = Saturate(i_d_um + i_s_um); 24 | %% (cont.) 25 | E_difference = sum((i_combined_um - i_input_um).^2,3); 26 | %% Test iteration {{TODO: make it... iterate}} 27 | aux = i_s; 28 | %% (cont.) 29 | w = 0.146; 30 | 31 | thr = mean2(E_difference) + 2*std(E_difference(:)); 32 | 33 | replaceThese = E_difference > thr; 34 | 35 | [row,col] = ind2sub(size(replaceThese),find(replaceThese)); 36 | 37 | paux = aux; 38 | 39 | for ind = 1:nnz(replaceThese) 40 | if row(ind) == 1 || col(ind) == 1 || row(ind) == nRow || col(ind) == nCol 41 | continue 42 | end 43 | Y_i_input = i_input(row(ind)-1:row(ind)+1,col(ind)-1:col(ind)+1,:); 44 | Y_i_input_um = i_input_um(row(ind)-1:row(ind)+1,col(ind)-1:col(ind)+1,:); 45 | Y_i_combined_um = i_combined_um(row(ind)-1:row(ind)+1,col(ind)-1:col(ind)+1,:); 46 | 47 | Y_i_input_col = reshape(Y_i_input,[9 3]); 48 | Y_i_input_um_col = reshape(Y_i_input_um,[9 3]); 49 | Y_i_combined_um_col = reshape(Y_i_combined_um,[9 3]); 50 | 51 | E_input_col = sum((Y_i_input_col(5,:)-Y_i_input_col).^2,2); 52 | E_um_col = sum((Y_i_input_um_col-Y_i_combined_um_col).^2,2); 53 | 54 | E_pp_col = w*E_input_col + (1-w)*E_um_col; 55 | 56 | [~,plausible] = min(E_pp_col); 57 | [pRow,pRol] = ind2sub([3 3],plausible); 58 | 59 | aux(row(ind),col(ind),:) = paux(row(ind)-2+pRow,col(ind)-2+pRol,:); 60 | end 61 | %% (cont.) 62 | if sqrt(immse(aux,paux)) < e || count >= 10 63 | break 64 | end 65 | %% Update i_d, i_s 66 | i_s = aux; 67 | i_d = Saturate(i_input - i_s); 68 | %% 69 | end % ENDWHILE 70 | %% 71 | Show.Difference(i_input-aux,i_input-i_s,10) 72 | 73 | % function Y = Saturate(X) 74 | 75 | % Y = min(1,max(0,X)); 76 | 77 | % end 78 | 79 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Highpass.m: -------------------------------------------------------------------------------- 1 | classdef Highpass 2 | %HIGHPASS Placeholder object for highpass functions 3 | % Just a temporary organization thing 4 | 5 | properties(Constant) 6 | % None yet 7 | end 8 | 9 | methods(Static) 10 | function imFilt = Median(imDbl) 11 | %MEDIAN Median complement highpass filter 12 | % imFilt = Highpass.Median(imDbl) returns filtered image. 13 | % 14 | % See also: medfilt2 15 | imFilt = zeros(size(imDbl)); 16 | nRows = size(imDbl,1); 17 | nCols = size(imDbl,2); 18 | nCh = size(imDbl,3); 19 | hsize = fix(min(nRows,nCols)/20)*2+1; % 1/10 factor obtained experimentally 20 | for iCh = 1:nCh 21 | imFilt(:,:,iCh) = medfilt2(imDbl(:,:,iCh),[hsize hsize],'symmetric'); 22 | end 23 | imFilt = imDbl-imFilt; 24 | imFilt = min(1,(max(0,imFilt))); 25 | end 26 | function imFilt = Spatial(imDbl) 27 | %SPATIAL Average complement highpass filter 28 | % imFilt = Highpass.Spatial(imDbl) returns filtered image. 29 | % 30 | % See also: fspecial imfilter 31 | nRows = size(imDbl,1); 32 | nCols = size(imDbl,2); 33 | hsize = fix(min(nRows,nCols)/32)*2+1; % 1/16 factor obtained experimentally 34 | imFilt = imDbl-imfilter(imDbl,fspecial('average',hsize),'symmetric'); 35 | imFilt = min(1,(max(0,imFilt))); 36 | end 37 | function imFilt = Wavelet(imDbl) 38 | %WAVELET Application-specific wavelet packet-based highpass filter 39 | % imFilt = Highpass.Wavelet(imDbl) returns a high-passed version of a 40 | % double-valued RGB image imDbl. The function has undefined behaviour for 41 | % unmet necessary conditions. 42 | % 43 | % Works by zeroing the approximation coefficients at the deepest possible 44 | % level for the 2-D wavelet packet decomposition of each channel. 45 | % 46 | % See also: wpdec2 47 | x = im2uint8(imDbl); 48 | wname = 'bior3.5'; 49 | level = wmaxlev(size(x),wname); 50 | t = wpdec2(x,level,wname); % plot(t) 51 | node = [level 0]; 52 | cfs = read(t,'data',node); 53 | cfs = zeros(size(cfs)); 54 | t = write(t,'data',node,cfs); 55 | imFilt = min(1,(max(0,im2double(uint8(wprec2(t)))))); 56 | end 57 | end 58 | end 59 | 60 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/FourierApproach.m: -------------------------------------------------------------------------------- 1 | src = double(imresize(imread('img\lady.bmp'),[256 NaN],'lanczos3')); 2 | src = src + 0.5*rand(size(src)); 3 | dst = src; 4 | [srcR,srcG,srcB] = imsplit(src); 5 | [dstR,dstG,dstB] = imsplit(dst); 6 | % 7 | total = sum(src,3); 8 | total3 = repmat(total,[1 1 3]); 9 | % 10 | tIdx = total<=eps; % total==0; 11 | tIdx3 = repmat(tIdx,[1 1 3]); 12 | % 13 | sigma = zeros(size(src)); 14 | sigma(~tIdx3) = src(~tIdx3)./total3(~tIdx3); % chromaticity 15 | % 16 | sigmaMax = max(sigma,[],3); 17 | sigmaMin = min(sigma,[],3); 18 | sigmaMin3 = repmat(sigmaMin,[1 1 3]); 19 | % 20 | sIdx = sigmaMin>=1/3-eps & sigmaMin<=1/3+eps; 21 | sIdx3 = repmat(sIdx,[1 1 3]); 22 | % 23 | lambda = ones(size(src))/3; 24 | lambda(~sIdx3) = (sigma(~sIdx3)-sigmaMin3(~sIdx3))./... 25 | (3*(lambda(~sIdx3)-sigmaMin3(~sIdx3))); 26 | lambdaMax = max(lambda,[],3); 27 | % 28 | clear idx idx3 sIdx sIdx3 sigmaMin3 tIdx tIdx3 total3 29 | 30 | count = uint8(0); 31 | while true 32 | % count = count + 1; 33 | % if count>=8 34 | % break 35 | % end 36 | % TODO: find a way to propagate diffuse to specular px 37 | h = fspecial('gaussian',[size(dst,1) size(dst,2)],max(size(dst,1),size(dst,2))/2); 38 | h = (h-min(h(:)))/(max(h(:))-min(h(:))); 39 | h = fftshift(h); 40 | % 41 | % Z = abs(fft2(zscore(sigmaMax))); 42 | % 43 | % m = (max(dst,[],3)./max(dst(:))).^4; % heightened highlights 44 | % M = abs(fft2(m)); 45 | % hloc = find(M>mean2(M)+3*std(M)); 46 | % hloc(hloc==1) = []; 47 | % 48 | % if isempty(hloc) 49 | % break 50 | % end 51 | % 52 | L = fft2(lambdaMax); 53 | LAbs = abs(L); 54 | LAng = angle(L); 55 | % 56 | S = fft2(sigmaMax); 57 | SAbs = abs(S); 58 | SAng = angle(S); 59 | % 60 | NAbs = SAbs; 61 | NAng = LAng; 62 | % NAng(hloc) = LAng(hloc); 63 | % 64 | sigmaMaxF = real(ifft2(h.*NAbs.*exp(1i*NAng))); 65 | sigmaMax = max(sigmaMax,sigmaMaxF); 66 | % 67 | idx = sigmaMax*3<=1; 68 | nz = sigmaMax~=1/3; 69 | sfi = zeros(size(srcR)); 70 | sfi(nz) = (max(max(... 71 | srcR(nz),srcG(nz)),srcB(nz)... 72 | )-sigmaMax(nz).*total(nz))./(1-3*sigmaMax(nz)); 73 | dstR(~idx) = srcR(~idx)-sfi(~idx); 74 | dstG(~idx) = srcG(~idx)-sfi(~idx); 75 | dstB(~idx) = srcB(~idx)-sfi(~idx); 76 | % 77 | dst = cat(3,dstR,dstG,dstB); 78 | if nnz(abs(sigmaMax-sigmaMaxF)>0.03)==0 79 | break 80 | end 81 | end 82 | Show.Difference(dst/255,src/255) 83 | %% 84 | % [lA,lH,lV,lD] = haart2(lambdaMax,level); 85 | % [sA,sH,sV,sD] = haart2(sigmaMax,level); 86 | % sigmaMaxF = ihaart2(sA,sH,sV,sD,0); 87 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Static.m: -------------------------------------------------------------------------------- 1 | classdef Static 2 | %STATIC Placeholder object for static functions 3 | % Exactly what the title says 4 | 5 | properties(Constant) 6 | % None yet 7 | end 8 | 9 | methods(Static) 10 | function dst = padNextPow2(src,value) 11 | [nRow,nCol,~] = size(src); 12 | [prePadRow,prePadCol,postPadRow,postPadCol] =... 13 | Static.getNextPow2PadVals(nRow,nCol); 14 | dst = padarray(src,[prePadRow prePadCol],value,'pre'); 15 | dst = padarray(dst,[postPadRow postPadCol],value,'post'); 16 | end 17 | function dst = unPadNextPow2(src,nRow,nCol) 18 | [prePadRow,prePadCol,postPadRow,postPadCol] =... 19 | Static.getNextPow2PadVals(nRow,nCol); 20 | dst = src(1+prePadRow:end-postPadRow,1+prePadCol:end-postPadCol,:); 21 | end 22 | function [prePadRow,prePadCol,postPadRow,postPadCol] =... 23 | getNextPow2PadVals(nRow,nCol) 24 | nRowNextPow2 = 2^nextpow2(nRow); 25 | nColNextPow2 = 2^nextpow2(nCol); 26 | prePadRow = floor((nRowNextPow2-nRow)/2); 27 | prePadCol = floor((nColNextPow2-nCol)/2); 28 | postPadRow = ceil((nRowNextPow2-nRow)/2); 29 | postPadCol = ceil((nColNextPow2-nCol)/2); 30 | end 31 | function dstF = progMedFilt2(dst,lev,sz) 32 | [nRow,nCol,nCh] = size(dst); % 2 for synth 33 | maxLev = nextpow2(min(nRow,nCol))-lev; % 1/2^(maxLev-1) = minimum scale 34 | dstLev{1} = dst; 35 | for iLev = 2:maxLev 36 | dstLev{iLev} = imresize(dstLev{iLev-1},0.5,... 37 | 'Method','bilinear','AntiAliasing',true); 38 | end 39 | dstLevF = dstLev; 40 | % roi = strel('disk',4,4).Neighborhood; 41 | % med = ceil(nnz(roi)/2); 42 | for iLev = 3:maxLev 43 | for iCh = 1:nCh 44 | dstLevF{iLev}(:,:,iCh) = ... 45 | medfilt2(dstLev{iLev}(:,:,iCh),sz,'symmetric'); 46 | % ordfilt2(dstLev{iLev}(:,:,iCh),med,roi,'symmetric'); 47 | end 48 | end 49 | for iLev = maxLev:-1:2 50 | dstLevF{iLev-1} = min(cat(4,... 51 | dstLevF{iLev-1},... 52 | imresize(dstLevF{iLev},... 53 | [size(dstLevF{iLev-1},1),size(dstLevF{iLev-1},2)],... 54 | 'Method','bilinear','AntiAliasing',true)),... 55 | [],4); 56 | end 57 | dstF = min(1,max(0,dstLevF{1})); 58 | end 59 | end 60 | end 61 | 62 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Demos.m: -------------------------------------------------------------------------------- 1 | %% Methods based on space transformation 2 | %% 3 | imInt = imread('img\mouse_cup.jpg'); 4 | imDbl = im2double(imInt); 5 | %% ROI-based segmentation and modified Shafer space 6 | %% 7 | clearvars -except imDbl 8 | mask = Mask.GrowHighlights(imDbl); 9 | mask = logical(max(mask,[],3)); 10 | stats = regionprops('table',mask,'Centroid','MajorAxisLength'); 11 | diameters = stats.MajorAxisLength; 12 | pad = ceil(max(diameters)); 13 | imProc = padarray(imDbl,[pad pad],'symmetric'); 14 | nCtds = size(stats,1); 15 | for iCtd = 1:nCtds 16 | coord = round(stats.Centroid(iCtd,:)); 17 | diam = stats.MajorAxisLength(iCtd); 18 | radius = ceil(diam/2); 19 | se = strel('disk',radius).Neighborhood; 20 | orig = floor((size(se)+1)/2); % roi center (row,col) 21 | r1 = coord(2) - orig(1) + 1 + pad; 22 | c1 = coord(1) - orig(2) + 1 + pad; 23 | r2 = r1 + size(se,1) - 1; 24 | c2 = c1 + size(se,2) - 1; 25 | crop = imProc(r1:r2,c1:c2,:); 26 | ref = GetNewShaferRef(crop); 27 | [imT,T] = NewShaferSpace(ref,crop,'fwd'); 28 | imT(:,:,2) = 0; 29 | newCrop = NewShaferSpace(T,imT,'rev'); 30 | imProc(r1:r2,c1:c2,:) = se.*newCrop + ~se.*imProc(r1:r2,c1:c2,:); 31 | end 32 | imNew = imProc(1+pad:size(imProc,1)-pad,1+pad:size(imProc,2)-pad,:); 33 | imNew = min(imNew,imDbl); 34 | figure(1), Show.Difference(imNew,imDbl) 35 | figure(2), Show.HistPair(imNew,imDbl,[0.7 1]) 36 | %% Compact ROI complete image transformation 37 | %% 38 | clearvars -except imDbl 39 | se = strel('rectangle',[5 5]).Neighborhood; 40 | orig = [3 3]; 41 | pad = 2; 42 | imNew = imDbl; 43 | nRe = 2; 44 | for iRe = 1:nRe 45 | disp(['Iteration #' num2str(iRe)]) 46 | imProc = padarray(imNew,[pad pad],'symmetric','both'); 47 | nRows = size(imProc,1); 48 | nCols = size(imProc,2); 49 | for iRow = 1+pad:nRows-pad 50 | for iCol = 1+pad:nCols-pad 51 | r1 = iRow - orig(1) + 1; 52 | c1 = iCol - orig(2) + 1; 53 | r2 = r1 + size(se,1) - 1; 54 | c2 = c1 + size(se,2) - 1; 55 | roi = imProc(r1:r2,c1:c2,:); 56 | [~,s] = imsplit(rgb2hsv(roi(orig(1),orig(2),:))); 57 | if s<0.2 58 | imNew(iRow-pad,iCol-pad,:) = 254/255*roi(orig(1),orig(2),:); 59 | continue 60 | end 61 | ref = roi; 62 | [roi,T] = NewShaferSpace(ref,roi,'fwd'); 63 | roi(:,:,2) = 0; % illuminant plane 64 | roi = NewShaferSpace(T,roi,'rev'); 65 | imNew(iRow-pad,iCol-pad,:) = min(1,max(0,roi(orig(1),orig(2),:))); 66 | end 67 | end 68 | end 69 | dr = 157:157+74; 70 | dc = 98:98+88; 71 | figure(1), Show.Difference(imNew(dr,dc,:),imDbl(dr,dc,:)) 72 | figure(2), Show.Difference(imNew,imDbl) 73 | figure(3), Show.HistPair(imNew,imDbl,[0.7 1]) 74 | 75 | -------------------------------------------------------------------------------- /Yamamoto2017/Yamamoto2017.m: -------------------------------------------------------------------------------- 1 | %% Import image to workspace 2 | i_input = im2double(imread('toys.ppm')); 3 | [nRow,nCol,nCh] = size(i_input); 4 | %% i = i_d + i_s 5 | i_d = qx_highlight_removal_bf(i_input); % or another highlight removal method 6 | i_s = min(1,max(0,(i_input - i_d))); 7 | %% Iteration constraints 8 | iterCount = uint8(0); 9 | maxIterCount = uint8(10); % uint8 type comparisons are faster in MATLAB 10 | epsilon = 0.2; 11 | %% While loop 12 | while true 13 | %% (cont.) 14 | k = 10; 15 | h = fspecial('average',3); 16 | i_input_bf = imfilter(i_input,h,'symmetric'); 17 | i_d_bf = imfilter(i_d, h,'symmetric'); 18 | i_s_bf = imfilter(i_s, h,'symmetric'); 19 | %% (cont.) 20 | i_input_um = Saturate(i_input + k*Saturate(i_input - i_input_bf)); 21 | i_d_um = Saturate(i_d + k*Saturate(i_d - i_d_bf )); 22 | i_s_um = Saturate(i_s + k*Saturate(i_s - i_s_bf )); 23 | %% (cont.) 24 | i_combined_um = Saturate(i_d_um + i_s_um); 25 | %% (cont.) 26 | % E_difference = sum((i_combined_um - i_input_um).^2,3); 27 | %% Test iteration {{TODO: make it... iterate}} 28 | aux = i_s; 29 | %% (cont.) 30 | omega = 0.3; 31 | 32 | % thr = mean2(E_difference) + 2*std(E_difference(:)); 33 | 34 | % replaceThese = E_difference > thr; 35 | replaceThese = logical(sum(double(i_d_um > i_input_um),3)==3); 36 | 37 | [row,col] = ind2sub(size(replaceThese),find(replaceThese)); 38 | 39 | paux = aux; 40 | 41 | for ind = 1:nnz(replaceThese) 42 | if row(ind) == 1 || col(ind) == 1 || row(ind) == nRow || col(ind) == nCol 43 | continue 44 | end 45 | Y_i_input = i_input(row(ind)-1:row(ind)+1,col(ind)-1:col(ind)+1,:); 46 | Y_i_input_um = i_input_um(row(ind)-1:row(ind)+1,col(ind)-1:col(ind)+1,:); 47 | Y_i_combined_um = i_combined_um(row(ind)-1:row(ind)+1,col(ind)-1:col(ind)+1,:); 48 | 49 | Y_i_input_col = reshape(Y_i_input,[9 3]); 50 | Y_i_input_um_col = reshape(Y_i_input_um,[9 3]); 51 | Y_i_combined_um_col = reshape(Y_i_combined_um,[9 3]); 52 | 53 | E_input_col = sum((Y_i_input_col(5,:)-Y_i_input_col).^2,2); 54 | E_um_col = sum((Y_i_input_um_col-Y_i_combined_um_col).^2,2); 55 | 56 | E_pp_col = omega*E_input_col + (1-omega)*E_um_col; 57 | 58 | [~,plausible] = min(E_pp_col); 59 | [pRow,pRol] = ind2sub([3 3],plausible); 60 | 61 | aux(row(ind),col(ind),:) = paux(row(ind)-2+pRow,col(ind)-2+pRol,:); 62 | end 63 | %% (cont.) 64 | if sqrt(immse(aux,paux)) < epsilon || iterCount >= maxIterCount 65 | break 66 | end 67 | %% Update i_d, i_s 68 | i_s = aux; 69 | i_d = Saturate(i_input - i_s); 70 | %% 71 | end % ENDWHILE 72 | %% 73 | imshow([i_input-aux i_input-i_s]) 74 | -------------------------------------------------------------------------------- /Tan2005/zIteration.m: -------------------------------------------------------------------------------- 1 | function src = zIteration(src,sfi,epsilon) 2 | [src,count] = zInit(src,sfi,epsilon); 3 | thR = 0.1; thG = 0.1; 4 | nY = size(src.rgb,1); 5 | nX = size(src.rgb,2); 6 | while true 7 | cr = z.Chroma_r(src.rgb(1:nY-1,1:nX-1,:)); 8 | cg = z.Chroma_g(src.rgb(1:nY-1,1:nX-1,:)); 9 | cr_next_x = z.Chroma_r(src.rgb(1:nY-1,2:nX,:)); 10 | cg_next_x = z.Chroma_g(src.rgb(1:nY-1,2:nX,:)); 11 | cr_next_y = z.Chroma_r(src.rgb(2:nY,1:nX-1,:)); 12 | cg_next_y = z.Chroma_g(src.rgb(2:nY,1:nX-1,:)); 13 | drx = cr_next_x - cr; 14 | dgx = cg_next_x - cg; 15 | dry = cr_next_y - cr; 16 | dgy = cg_next_y - cg; 17 | iMaxChroma = z.MaxChroma(src.rgb); 18 | for iY = 1:nY-1 19 | for iX = 1:nX-1 20 | if src.i(iY,iX) == z.CAMERA_DARK 21 | continue 22 | end 23 | if src.i(iY,iX) == z.SPECULARX 24 | if abs(drx(iY,iX)) > thR && abs(dgx(iY,iX)) > thG 25 | src.i(iY,iX) = z.BOUNDARY; 26 | continue 27 | end 28 | if abs(iMaxChroma(iY,iX) - iMaxChroma(iY,iX+1)) < 0.01 29 | src.i(iY,iX) = z.NOISE; 30 | continue 31 | end 32 | if iMaxChroma(iY,iX) < iMaxChroma(iY,iX+1) 33 | [src.rgb(iY,iX,:),src.i(iY,iX)] = zSpecular2Diffuse(src.rgb(iY,iX,:),src.i(iY,iX),iMaxChroma(iY,iX+1)); 34 | src.i(iY,iX) = z.DIFFUSE; 35 | src.i(iY,iX+1) = z.DIFFUSE; 36 | else 37 | [src.rgb(iY,iX+1,:),src.i(iY,iX+1)] = zSpecular2Diffuse(src.rgb(iY,iX+1,:),src.i(iY,iX+1),iMaxChroma(iY,iX)); 38 | src.i(iY,iX) = z.DIFFUSE; 39 | src.i(iY,iX+1) = z.DIFFUSE; 40 | end 41 | end 42 | % 43 | if src.i(iY,iX) == z.SPECULARY 44 | if abs(dry(iY,iX)) > thR && abs(dgy(iY,iX)) > thG 45 | src.i(iY,iX) = z.BOUNDARY; 46 | continue 47 | end 48 | if abs(iMaxChroma(iY,iX) - iMaxChroma(iY+1,iX)) < 0.01 49 | src.i(iY,iX) = z.NOISE; 50 | continue 51 | end 52 | if iMaxChroma(iY,iX) < iMaxChroma(iY+1,iX) 53 | [src.rgb(iY,iX,:),src.i(iY,iX)] = zSpecular2Diffuse(src.rgb(iY,iX,:),src.i(iY,iX),iMaxChroma(iY+1,iX)); 54 | src.i(iY,iX) = z.DIFFUSE; 55 | src.i(iY+1,iX) = z.DIFFUSE; 56 | else 57 | [src.rgb(iY+1,iX,:),src.i(iY+1,iX)] = zSpecular2Diffuse(src.rgb(iY+1,iX,:),src.i(iY+1,iX),iMaxChroma(iY,iX)); 58 | src.i(iY,iX) = z.DIFFUSE; 59 | src.i(iY+1,iX) = z.DIFFUSE; 60 | end 61 | end 62 | end 63 | end 64 | pcount = count; 65 | [src,count] = zInit(src,sfi,epsilon); 66 | if count < 0 67 | break 68 | end 69 | if pcount <= count 70 | break 71 | end 72 | end 73 | src = zResetLabels(src); 74 | end 75 | 76 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Interp.m: -------------------------------------------------------------------------------- 1 | imInt = imresize(imread('img\toys.ppm'),[256 NaN],'lanczos3'); 2 | imDbl = im2double(imInt); 3 | %% 4 | clearvars -except imDbl 5 | %% 6 | imNew = imDbl; 7 | [nR,nG,nB] = imsplit(imNew); 8 | %% 9 | nRe = 50; 10 | %% 11 | for iRe = 1:nRe 12 | mask = Mask.NearClip(imNew); 13 | mask = Mask.GrowHighlights([],mask); 14 | [maskR,maskG,maskB] = imsplit(mask); 15 | nR = InterpCh(nR,boolean(maskR)); 16 | nG = InterpCh(nG,boolean(maskG)); 17 | nB = InterpCh(nB,boolean(maskB)); 18 | imNew = cat(3,nR,nG,nB); 19 | end 20 | %% 21 | dr = 59:59+32-1; 22 | dc = 147:147+32-1; 23 | Show.Difference(imNew(dr,dc,:),imDbl(dr,dc,:)) 24 | %% 25 | Show.Difference(imNew,imDbl) 26 | %% 27 | % tmp = mask.'; 28 | % area(mask(:),'FaceAlpha',0.5,'FaceColor','r','EdgeColor','r') 29 | % hold on 30 | % area(tmp(:),'FaceAlpha',0.5,'FaceColor','b','EdgeColor','b') 31 | % hold off 32 | % axis tight 33 | % grid minor 34 | %% 35 | % imshow([mask logical(vsep) maskT]) 36 | % imshow([ch vsep chT]) 37 | %% 38 | ch = nR; 39 | for iRe = 1:2 40 | disp(['Iteration #' num2str(iRe) '...']) 41 | ch = padarray(ch,[1 1],'symmetric'); 42 | inter = zeros(size(ch)); 43 | nRows = size(ch,1); 44 | nCols = size(ch,2); 45 | for iRow = 2:nRows-1 46 | for iCol = 2:nCols-1 47 | dr = iRow-1:iRow+1; 48 | dc = iCol-1:iCol+1; 49 | mask = GenInterpROIMask(ch(dr,dc)); 50 | inter(iRow,iCol) = InterpROI(ch(dr,dc),mask); 51 | end 52 | end 53 | inter = inter(2:end-1,2:end-1); 54 | ch = inter; 55 | end 56 | %% 57 | ref = nR; 58 | %% 59 | nPad = 20; 60 | ref = padarray(ref,[nPad nPad],'symmetric'); 61 | A = ref; 62 | for iPad = 1:nPad 63 | fun = @(c) InterpROI(c,GenInterpROIMask(c)); 64 | A = nlfilter(A,[3 3],fun); 65 | end 66 | A = A(1+nPad:end-nPad,1+nPad:end-nPad); 67 | ref = ref(1+nPad:end-nPad,1+nPad:end-nPad); 68 | %% 69 | Show.Difference(repmat(A,[1 1 3]),repmat(ref,[1 1 3])) 70 | %% 71 | function new = InterpROI(roi,mask) 72 | % orig = floor((size(mask)+1)/2); 73 | if mask(2,2) == false 74 | new = roi(2,2); 75 | return 76 | end 77 | maskT = mask.'; % line = roiT(maskT); 78 | roiT = roi.'; % column = roi (mask); 79 | % 80 | valx = maskT(:); % horizontal mask 81 | x = roiT(:); 82 | x(valx) = interp1(find(~valx),x(~valx),find(valx),'spline','extrap'); 83 | % 84 | valy = mask(:); % vertical mask 85 | y = roi(:); 86 | y(valy) = interp1(find(~valy),y(~valy),find(valy),'spline','extrap'); 87 | % 88 | x = reshape(x,size(roiT)).'; 89 | y = reshape(y,size(roi)); 90 | % 91 | new = min(x(2,2),y(2,2)); 92 | end 93 | %% 94 | function mask = GenInterpROIMask(roi) 95 | mask = false(size(roi)); 96 | if roi(2,2) > 10/255 && roi(2,2) >= getfield(sort(roi(:)),{7}) 97 | mask(2,2) = true; 98 | end 99 | end 100 | function newCh = InterpCh(ch,mask) 101 | maskT = mask.'; % line = chT(maskT); 102 | chT = ch.'; % column = ch(mask); 103 | % 104 | valx = maskT(:); % horizontal mask 105 | x = chT(:); 106 | x(valx) = interp1(find(~valx),x(~valx),find(valx),'spline','extrap'); 107 | % 108 | valy = mask(:); % vertical mask 109 | y = ch(:); 110 | y(valy) = interp1(find(~valy),y(~valy),find(valy),'spline','extrap'); 111 | % 112 | x = reshape(x,size(chT)).'; 113 | y = reshape(y,size(ch)); 114 | % 115 | newCh = min(x,y); 116 | end -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Tests.m: -------------------------------------------------------------------------------- 1 | imInt = imresize(imread('green.jpg'),[256 NaN],'lanczos3'); 2 | imDbl = im2double(imInt); 3 | %% 4 | clearvars -except imDbl 5 | %% 6 | vsep = repmat(ones([size(imDbl,1) 1]),[1 1 3]); 7 | %% 8 | [imT,T] = NewShaferSpace(imDbl,imDbl,'fwd'); 9 | [imR,~] = NewShaferSpace(imDbl,imT,'rev'); 10 | [body,ill,err] = SplitPlanesToRGB(imT,T); 11 | imshow([body vsep ill vsep err]) 12 | title('[(a) Body, (b) Reflection, (c) Error] decomposition planes') 13 | QualityMetrics(imR,imDbl) 14 | %% 15 | PlotNewShaferSpace(imDbl,T,'g') 16 | view([-120 15]) 17 | %% 18 | clearvars -except imDbl vsep 19 | %% 20 | [imT,T] = TSpace(imDbl,'fwd'); 21 | [imR,~] = TSpace(imT,'rev'); 22 | [neu,gm,ill] = SplitPlanesToRGB(imT,T); 23 | imshow([neu vsep gm vsep ill]) 24 | title('[(a) Neutral, (b) Green-magenta, (c) Illuminant] planes') 25 | QualityMetrics(imR,imDbl) 26 | %% 27 | % iRow = [1+pad,nRows-pad] 28 | % iCol = [1+pad,nCols-pad] 29 | % r1 = iRow - orig(1) + 1 30 | % c1 = iCol - orig(2) + 1 31 | % r2 = r1 + size(se,1) - 1 32 | % c2 = c1 + size(se,2) - 1 33 | % r1(1):r2(1) 34 | % c1(1):c2(1) 35 | % r1(2):r2(2) 36 | % c1(2):c2(2) 37 | %% 38 | % C = CH; L = SH; 39 | % wthrmngr('dw2dcompGBL','rem_n0',imDbl) 40 | % wthrmngr('dw2dcompGBL','bal_sn',C,L) 41 | % wthrmngr('dw2dcompGBL','sqrtbal_sn',C,L) 42 | % max(wthrmngr('dw2dcompLVL','scarcehi',C,L,10),[],'all')%where 2.5 < alpha < 10 43 | % max(wthrmngr('dw2dcompLVL','scarceme',C,L,2.5),[],'all')%where 1.5 < alpha < 2.5 44 | % max(wthrmngr('dw2dcompLVL','scarcelo',C,L,2),[],'all')%where 1 < alpha < 2 45 | % max(wthrmngr('dw2ddenoLVL','sqrtbal_sn',C,L),[],'all') 46 | % max(wthrmngr('dw2ddenoLVL','penalhi',C,L,10),[],'all')%, where 2.5 < alpha < 10 47 | % max(wthrmngr('dw2ddenoLVL','penalme',C,L,2.5),[],'all')%, where 1.5 < alpha < 2.5 48 | % max(wthrmngr('dw2ddenoLVL','penallo',C,L,2),[],'all')%, where 1 < alpha < 2 49 | % max(wthrmngr('dw2ddenoLVL','sqtwolog',C,L,'one'),[],'all') 50 | %% 51 | function [c1,c2,c3] = SplitPlanesToRGB(imT,T) 52 | c1 = cat(3,T(1,1)*imT(:,:,1),T(1,2)*imT(:,:,1),T(1,3)*imT(:,:,1)); 53 | c2 = cat(3,T(2,1)*imT(:,:,2),T(2,2)*imT(:,:,2),T(2,3)*imT(:,:,2)); 54 | c3 = cat(3,T(3,1)*imT(:,:,3),T(3,2)*imT(:,:,3),T(3,3)*imT(:,:,3)); 55 | end 56 | function PlotNewShaferSpace(imDbl,T,flag) 57 | vv = T(1,:); 58 | ww = T(2,:); 59 | % nn = T(3,:); 60 | r = reshape(imDbl(:,:,1),[],1); 61 | g = reshape(imDbl(:,:,2),[],1); 62 | b = reshape(imDbl(:,:,3),[],1); 63 | xx = [0 mean(r,'all') 1]'; 64 | yy = [0 mean(g,'all') 1]'; 65 | zz = [0 mean(b,'all') 1]'; 66 | N = length(xx); 67 | O = ones(N,1); 68 | C = [xx yy O]\zz; 69 | x = linspace(0,1,128); 70 | y = linspace(0,1,128); 71 | [xx,yy] = meshgrid(x,y); 72 | zzft = C(1)*xx + C(2)*yy + C(3); 73 | tmpR = downsample(r,32); 74 | tmpG = downsample(g,32); 75 | tmpB = downsample(b,32); 76 | clf reset 77 | scatter3(tmpR,tmpG,tmpB,flag,'.') 78 | hold on 79 | surf(xx,yy,zzft,'edgecolor','none') 80 | colormap gray 81 | plot3([0 vv(1)],[0 vv(2)],[0 vv(3)],'y',... 82 | 'LineWidth',2,... 83 | 'Marker','.',... 84 | 'MarkerSize',16) 85 | plot3(vv(1)+[0 ww(1)],vv(2)+[0 ww(2)],vv(3)+[0 ww(3)],'y',... 86 | 'LineWidth',2,... 87 | 'Marker','.',... 88 | 'MarkerSize',16) 89 | plot3([0 ww(1)],[0 ww(2)],[0 ww(3)],'y',... 90 | 'LineWidth',2,... 91 | 'Marker','.',... 92 | 'MarkerSize',16) 93 | plot3(ww(1)+[0 vv(1)],ww(2)+[0 vv(2)],ww(3)+[0 vv(3)],'y',... 94 | 'LineWidth',2,... 95 | 'Marker','.',... 96 | 'MarkerSize',16) 97 | hold off 98 | title('RGB space') 99 | legend({'(R,G,B) scatter','Plane fit','Decomposition vectors'},... 100 | 'Box','off') 101 | xlabel('R'), ylabel('G'), zlabel('B') 102 | xlim([0 1]), ylim([0 1]), zlim([0 1]) 103 | axis square 104 | grid minor 105 | view([-45 15]) 106 | end 107 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Mask.m: -------------------------------------------------------------------------------- 1 | classdef Mask 2 | %MASK Placeholder object for mask functions 3 | % Just a temporary organization thing 4 | 5 | properties(Constant) 6 | % None yet 7 | end 8 | 9 | methods(Static) 10 | function nearClip = NearClip(imDbl) 11 | %NEARCLIP Gets near-clip pixels 12 | % nearClip = Mask.NearClip(imDbl) returns a mask containing only 13 | % maximum values locations for each channel. 14 | [r,g,b] = imsplit(imDbl); 15 | r(r thr 46 | scaledMask = max(0,min(1,(v-thr)/(maxv-thr))).^pow; 47 | else 48 | scaledMask = v; 49 | scaledMask(scaledMask 1 63 | error(['Input image D must be a double precision ',... 64 | 'matrix of size NxMx1 or NxMx3 on the closed ',... 65 | 'interval [0,1].']); 66 | end 67 | 68 | % Verify bilateral filter window size. 69 | if ~exist('w','var') || isempty(w) || ... 70 | numel(w) ~= 1 || w < 1 71 | w = 5; 72 | end 73 | w = ceil(w); 74 | 75 | % Verify bilateral filter standard deviations. 76 | if ~exist('sigma','var') || isempty(sigma) || ... 77 | numel(sigma) ~= 2 || sigma(1) <= 0 || sigma(2) <= 0 78 | sigma = [3 0.1]; 79 | end 80 | 81 | % Apply either grayscale or color bilateral filtering. 82 | if size(D,3) == 1 83 | B = jbfltGray(D,C,w,sigma(1),sigma(2)); 84 | else 85 | B = jbfltGray(D,C,w,sigma(1),sigma(2)); 86 | end 87 | 88 | 89 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 90 | % Implements bilateral filtering for grayscale images. 91 | function B = jbfltGray(D,C,w,sigma_d,sigma_r) 92 | 93 | % Pre-compute Gaussian distance weights. 94 | [X,Y] = meshgrid(-w:w,-w:w); 95 | G = exp(-(X.^2+Y.^2)/(2*sigma_d^2)); 96 | 97 | % Create waitbar. 98 | %h = waitbar(0,'Applying bilateral filter on gray image...'); 99 | %set(h,'Name','Bilateral Filter Progress'); 100 | 101 | % Apply bilateral filter. 102 | dim = size(D); 103 | B = zeros(dim); 104 | for i = 1:dim(1) 105 | for j = 1:dim(2) 106 | 107 | % Extract local region. 108 | iMin = max(i-w,1); 109 | iMax = min(i+w,dim(1)); 110 | jMin = max(j-w,1); 111 | jMax = min(j+w,dim(2)); 112 | I = D(iMin:iMax,jMin:jMax); 113 | 114 | % To compute weights from the color image 115 | J = C(iMin:iMax,jMin:jMax); 116 | 117 | % Compute Gaussian intensity weights according to the color image 118 | H = exp(-(J-C(i,j)).^2/(2*sigma_r^2)); 119 | 120 | % Calculate bilateral filter response. 121 | F = H.*G((iMin:iMax)-i+w+1,(jMin:jMax)-j+w+1); 122 | B(i,j) = sum(F(:).*I(:))/sum(F(:)); 123 | 124 | end 125 | %waitbar(i/dim(1)); 126 | end 127 | 128 | % Close waitbar. 129 | %close(h); 130 | -------------------------------------------------------------------------------- /Yang2010/bfilter2.m: -------------------------------------------------------------------------------- 1 | function img_out = bfilter2(image1, image2, n, sigma1, sigma2) 2 | %bfilter2 function: perfrom two dimensional bilateral gaussian filtering. 3 | %The standard deviations of the bilateral filter are given by sigma1 and 4 | %sigma2, where the standard deviation of spatial-domain is given by sigma1 5 | % and the standard deviation intensity-domain is given by sigma2. 6 | %This function presents both bilateral filter and joint-bilateral filter. 7 | %If you use the same image as image1 and image2, it is the normal bilateral 8 | %filter; however, if you use different images in image1 and image2, you can 9 | %use it as joint-bilateral filter, where the intensity-domain (range weight) 10 | %calculations are performed using image2 and the spatial-domain (space weight) 11 | %calculations are performed using image1. 12 | % 13 | %Usage: 14 | % %Example1: normal bilateral filter using 5x5 kernel, spatial-sigma=6, and 15 | % %intensity-sigma= 0.25: 16 | % image=bfilter2(I1,I1,5,1.2,0.25); 17 | % %Example2: joint-bilateral filter using 5x5 kernel, spatial-sigma=1.2, 18 | % %and range-sigma= 0.25, the spatial-domain calculations are performed 19 | % %using image (I1) and the intensity-domain calulcations (range weight) 20 | % %are performed using image (I2): 21 | % image=bfilter2(I1,I2,5,1.2,0.25); 22 | % %Example3: use the default values for n, sigma1, and sigma2 23 | % image=bfilter2(I1); 24 | % 25 | %Input: 26 | % -image1: the spatial-domain image 27 | % -image2: the intensity-domain (range weight) image (use the same image 28 | % for the normal bilateral filter. Use different images for joint-bilateral 29 | % filter. 30 | % (default, use the same image; i.e. image2=image1) 31 | % -n: kernel (window) size [nxn], should be odd number (default=5) 32 | % -sigma1: the standard deviation of spatial-domain (default=1.2) 33 | % sigma2: the standard deviation of intensity-domain (default=0.25) 34 | % 35 | %Author: Mahmoud Afifi, York University. 36 | 37 | 38 | % Copyright (c) 2017, mahmoud afifi 39 | % All rights reserved. 40 | % 41 | % Redistribution and use in source and binary forms, with or without 42 | % modification, are permitted provided that the following conditions are met: 43 | % 44 | % * Redistributions of source code must retain the above copyright notice, this 45 | % list of conditions and the following disclaimer. 46 | % 47 | % * Redistributions in binary form must reproduce the above copyright notice, 48 | % this list of conditions and the following disclaimer in the documentation 49 | % and/or other materials provided with the distribution 50 | % * Neither the name of York University nor the names of its 51 | % contributors may be used to endorse or promote products derived from this 52 | % software without specific prior written permission. 53 | % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 54 | % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 | % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 56 | % DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 57 | % FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 | % DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 59 | % SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 60 | % CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 61 | % OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 62 | % OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 | 64 | 65 | %argument's check 66 | if nargin<1 67 | error('Too few input arguments'); 68 | elseif nargin<2 69 | image2=image1; 70 | n=5; 71 | sigma1=1.2; 72 | sigma2=0.25; 73 | elseif nargin<3 74 | n=5; 75 | sigma1=1.2; 76 | sigma2=0.25; 77 | elseif nargin<4 78 | sigma1=1.2; 79 | sigma2=0.25; 80 | elseif nargin<5 81 | sigma2=0.25; 82 | end 83 | 84 | %kernel size check 85 | if mod(n,2)==0 86 | error('Please use odd number for kernel size'); 87 | end 88 | %dimensionality check 89 | if size(image1,1)~=size(image2,1) || size(image1,2)~=size(image2,2) || ... 90 | size(image1,3)~=size(image2,3) 91 | error('Both images should have the same dimensions and number of color channels'); 92 | end 93 | 94 | 95 | % display('processing...'); 96 | 97 | w=floor(n/2); 98 | 99 | % spatial-domain weights. 100 | [X,Y] = meshgrid(-w:w,-w:w); 101 | gs = exp(-(X.^2+Y.^2)/(2*sigma1^2)); 102 | 103 | %normalize images 104 | if isa(image1,'uint8')==1 105 | image1=double(image1)/255; 106 | end 107 | 108 | if isa(image2,'uint8')==1 109 | image2=double(image2)/255; 110 | end 111 | 112 | %intialize img_out 113 | img_out=zeros(size(image1,1),size(image1,2),size(image1,3)); 114 | %padd both iamges 115 | image1=padarray(image1,[w w],'replicate','both'); 116 | image2=padarray(image2,[w w],'replicate','both'); 117 | for i=ceil(n/2):size(image1,1)-w 118 | for j=ceil(n/2):size(image1,2)-w 119 | patch1(:,:,:)=image1(i-w:i+w,j-w:j+w,:); 120 | patch2(:,:,:)=image2(i-w:i+w,j-w:j+w,:); 121 | d=(repmat(image2(i,j,:),[n,n])-patch2).^2; 122 | % intensity-domain weights. (range weights) 123 | gr=exp(-(d)/(2*sigma2^2)); 124 | for c=1:size(image1,3) 125 | g(:,:,c)=gs.*gr(:,:,c); %bilateral filter 126 | normfactor=1/sum(sum(g(:,:,c))); %normalization factor 127 | %apply equation: 128 | %out[i]=normfactor*sum (kernel * image) 129 | img_out(i-ceil(n/2)+1,j-ceil(n/2)+1,c)=... 130 | sum(sum(g(:,:,c).*patch1(:,:,c)))*normfactor; 131 | % imshow(img_out,[]); 132 | end 133 | 134 | end 135 | end 136 | img_out=uint8(img_out*255); 137 | end 138 | 139 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/Ctds.m: -------------------------------------------------------------------------------- 1 | %% Methods based on space transformation 2 | 3 | clearvars 4 | fname = {'blue.jpg','fish.ppm','green.jpg','head.ppm','mix.jpg',... 5 | 'plastic.jpg','red.jpg','toys.ppm'}; 6 | nFiles = length(fname); 7 | for iFile = 1:nFiles 8 | src{iFile} = im2double(imresize(imread(fname{iFile}),[256 NaN],'lanczos3')); 9 | end 10 | %% ROI-based segmentation and modified Shafer space 11 | %% 12 | imDbl = src{5}; 13 | vsep = repmat(ones([size(imDbl,1) 1]),[1 1 3]); 14 | %% 15 | nc = Mask.NearClip(imDbl); 16 | nc = logical(max(nc,[],3)); 17 | stats = regionprops('table',nc,'Centroid',... 18 | 'MajorAxisLength'); 19 | centers = stats.Centroid; 20 | diameters = stats.MajorAxisLength; 21 | radii = ceil(diameters/2); 22 | imshow([imDbl vsep repmat(min(imDbl,[],3),[1 1 3])]) 23 | hold on 24 | viscircles(centers,radii); 25 | viscircles(centers + [size(imDbl,1)+1,0],radii); 26 | title(['Location of near-clip centroids on:' newline... 27 | '(a) Reference, (b) Specular-invariant mask']) 28 | hold off 29 | %% 30 | clearvars -except fname src nFiles 31 | radii = []; 32 | for iFile = 1:nFiles 33 | nc{iFile} = Mask.NearClip(src{iFile}); 34 | nc{iFile} = logical(max(nc{iFile},[],3)); 35 | stats{iFile} = regionprops('table',nc{iFile},'Centroid',... 36 | 'MajorAxisLength'); 37 | centers{iFile} = stats{iFile}.Centroid; 38 | diameters{iFile} = stats{iFile}.MajorAxisLength; 39 | radii = [radii; diameters{iFile}/2]; 40 | end 41 | %% 42 | r2db = radii; 43 | r2db(r2db<1) = 1; 44 | r2db = 1.4427*log(r2db); % inv: exp(val/1.4427) 45 | subplot(2,1,1) 46 | histogram(radii), axis tight, grid minor 47 | xline(mean(radii),'r-.','LineWidth',4); 48 | xline(mean(radii)+std(radii),'r-.','LineWidth',3); 49 | xline(mean(radii)+2*std(radii),'r-.','LineWidth',2); 50 | xline(mean(radii)+3*std(radii),'r-.','LineWidth',2); 51 | title('Radii distribution') 52 | legend({'Radii','\mu','\mu+\sigma','\mu+2\sigma','\mu+3\sigma'},'EdgeColor','w') 53 | subplot(2,1,2) 54 | histogram(r2db), axis tight, grid minor 55 | xline(mean(r2db),'r-.','LineWidth',4); 56 | xline(mean(r2db)+std(r2db),'r-.','LineWidth',3); 57 | xline(mean(r2db)+2*std(r2db),'r-.','LineWidth',2); 58 | xline(mean(r2db)+3*std(r2db),'r-.','LineWidth',1); 59 | title('In natural logarithm scale') 60 | legend({'Radii (dB)','\mu','\mu+\sigma','\mu+2\sigma','\mu+3\sigma'},'EdgeColor','w') 61 | %% 62 | clearvars 63 | %% 64 | imDbl = im2double(imresize(imread('mix.jpg'),[NaN 256],'lanczos3')); 65 | [~,s] = imsplit(rgb2hsv(imDbl)); 66 | nc = max(Mask.NearClip(imDbl),[],3); 67 | m = CtdMin(imDbl); 68 | imshow([m,s,nc]) 69 | title('(a) Minimum values between channels, (b) Saturation (c) Near-clip') 70 | hst = imhist(s)/numel(s); 71 | cdf = cumsum(hst); 72 | q1 = (find(cdf>=0.25,1)-1)/255; 73 | mu = mean2(s(s 4095 106 | break 107 | end 108 | end 109 | new = cfi; 110 | Show.Difference(new,src) 111 | Show.HistPair(new,src,[0.7 1]) 112 | %% 113 | function [cfi,esc] = CtdIteration(src,cfi) % ,pcoord,pradii 114 | [coord,radii] = CtdFind(cfi); 115 | [coord,radii,esc] = CtdTrim(coord,radii); % ,pcoord,pradii 116 | if esc 117 | return 118 | end 119 | pad = max(radii); 120 | src = padarray(src,[pad pad],'symmetric'); 121 | cfi = padarray(cfi,[pad pad],'symmetric'); 122 | nCtds = size(coord,1); 123 | for iCtd = 1:nCtds 124 | se = strel('disk',radii(iCtd)).Neighborhood; 125 | orig = floor((size(se)+1)/2); % roi center (row,col) 126 | r1 = coord(iCtd,2) - orig(1) + 1 + pad; 127 | c1 = coord(iCtd,1) - orig(2) + 1 + pad; 128 | r2 = r1 + size(se,1) - 1; 129 | c2 = c1 + size(se,2) - 1; 130 | crop = cfi(r1:r2,c1:c2,:); 131 | [~,s] = imsplit(rgb2hsv(src(r1:r2,c1:c2,:))); 132 | if min(s(:))<0.2 133 | % 134 | cfi(r1:r2,c1:c2,:) = se.*CtdSaturate(cfi(r1:r2,c1:c2,:)-1/255)+... 135 | ~se.*cfi(r1:r2,c1:c2,:); 136 | % 137 | continue 138 | end 139 | ref = GetNewShaferRef(crop); 140 | [imT,T] = NewShaferSpace(ref,crop,'fwd'); 141 | imT(:,:,2) = 0; 142 | newCrop = NewShaferSpace(T,imT,'rev'); 143 | % 144 | cfi(r1:r2,c1:c2,:) = se.*CtdSaturate((0.5*newCrop + 0.5*cfi(r1:r2,c1:c2,:))-1/255)+... 145 | ~se.*cfi(r1:r2,c1:c2,:); 146 | % 147 | end 148 | cfi = cfi(1+pad:size(cfi,1)-pad,1+pad:size(cfi,2)-pad,:); 149 | end 150 | % 151 | % 152 | function [coord,radii] = CtdFind(cfi) 153 | nc = Mask.NearClip(cfi); 154 | nc = logical(max(nc,[],3)); 155 | stats = regionprops('table',nc,'Centroid','MajorAxisLength'); 156 | coord = round(stats.Centroid); 157 | diam = stats.MajorAxisLength; 158 | radii = ceil(diam/2); 159 | end 160 | % 161 | % 162 | function [coord,radii,esc] = CtdTrim(coord,radii) % ,pcoord,pradii 163 | % idx = radii<=median(radii)+1; 164 | if ~isempty(coord) || ~isempty(radii) % nnz(idx)>0 165 | esc = false; 166 | % coord = coord(idx,:); 167 | % radii = radii(idx); 168 | else 169 | esc = true; 170 | end 171 | end 172 | % 173 | % 174 | function y = CtdSaturate(x) 175 | y = min(1,max(0,x)); 176 | end 177 | % 178 | % 179 | function m = CtdMin(x) 180 | m = min(x,[],3); 181 | end 182 | -------------------------------------------------------------------------------- /Ramos2019/OlderStuff/NewShen.m: -------------------------------------------------------------------------------- 1 | %% Import images 2 | fname = {... 3 | ...% (1) (2) (3) (4) 4 | 'animals.bmp','cups.bmp','fruit.bmp','masks.bmp',... 5 | ...% (5) (6) (7) (8) (9) (10) 6 | 'circle.ppm','fish.ppm','head.ppm','pear.ppm','toys.ppm','synth.ppm',... 7 | ...%(11) (12) (13) (14) (15) 8 | 'lady.bmp','rabbit.bmp','train.bmp','watermelon.bmp','wood.bmp'... 9 | }; 10 | 11 | gt = {... 12 | ...% (1) (2) (3) (4) 13 | 'animals_gt.bmp','cups_gt.bmp','fruit_gt.bmp','masks_gt.bmp'... 14 | }; 15 | %% 16 | V1 = imresize(im2double(imread(fname{4})),[NaN 200]); 17 | V2 = im2double(imread(fname{10})); 18 | Vycc1 = rgb2ycbcr(V1); 19 | Vycc2 = rgb2ycbcr(V2); 20 | [y1,cb1,cr1] = imsplit(Vycc1); 21 | [y2,cb2,cr2] = imsplit(Vycc2); 22 | figure(1) 23 | imshow([V1 repmat([y1 cb1 cr1],[1 1 3]); 24 | V2 repmat([y2 cb2 cr2],[1 1 3])]) 25 | %% Approach 1: not final either 26 | num = [4 2 3 1]; 27 | for idx = 1:4 28 | img = num(idx); 29 | ref = imresize(im2double(imread(fname{img})),1); 30 | gnd = imresize(im2double(imread( gt{img})),1); 31 | V = ref; 32 | 33 | counter = uint8(0); 34 | while true 35 | [nRow,nCol,~] = size(V); 36 | Vmin = min(V,[],3); 37 | Vsf = V - Saturate(Vmin-mean2(Vmin(:))); 38 | Vmsf = V - Vmin + mean2(Vmin(:)); 39 | [Y,Cb,Cr] = imsplit(rgb2ycbcr(V)); % reshape(,[numel(V)/3 1 3]) 40 | [dY,dCb,dCr] = imsplit(rgb2ycbcr(Vsf)); % reshape(,[numel(V)/3 1 3]) 41 | % [sCb,iCb] = sort(Cb); 42 | % [sCr,iCr] = sort(Cr); 43 | diffCddts = ~imbinarize(max(getCandidates(V,Vmsf),[],3)); 44 | Ydiff = Y(diffCddts); 45 | if isempty(Ydiff) 46 | break 47 | end 48 | % Ydiff = (Ydiff-min(Ydiff(:)))/range(Y(:)); 49 | dY = dY - min(dY(:)) + min(Y(:)); 50 | in = [min(dY(:)); max(dY(:))]; 51 | out= [min(Ydiff(:)); max(Ydiff(:))]; 52 | gamma = mean2(dY(:))/mean2(Y(:)); 53 | dYadj = reshape(imadjust(dY(:),in,out,gamma),nRow,nCol); 54 | 55 | Vnew = ycbcr2rgb(cat(3,dYadj,dCb,dCr)); 56 | Vresidual = min(Saturate(V-Vnew),[],3); 57 | if range(Vresidual(:)) <= 0.03 || counter >= 4 58 | break 59 | end 60 | V = V - Vresidual; 61 | counter = counter + 1; 62 | end 63 | % figure(img) 64 | subplot(4,1,idx), Show.Difference(V,gnd),... 65 | title(['PSNR = ' num2str(psnr(V,gnd))]) 66 | end 67 | % figure(2) 68 | % scatter3(Y(:),Cb(:),Cr(:),'r.') 69 | % hold on 70 | % scatter3(dY(:),dCb(:),dCr(:),'k.') 71 | % scatter3(dYadj(:),Cb(:),Cr(:),'b.') 72 | % hold off 73 | % xlabel('Y'), ylabel('Cb'), zlabel('Cr') 74 | % legend({'Y','dark Y','adj. dark Y'}) 75 | % axis tight, grid minor 76 | % view([60 60]) 77 | %% Approach 2: final (beats SOA except for fruits) 78 | % clearvars -except fname gt 79 | V = im2double(imread(fname{1})); 80 | G = im2double(imread( gt{1})); 81 | [nRow,nCol,~] = size(V); 82 | Vsfi = V; 83 | VYcc = rgb2ycbcr(V); 84 | VY = VYcc(:,:,1); 85 | % VsatMask = getSatMask(V,1,1); % add VsatMaskValid flag 86 | % figure(1), imshow(loLoSatMask) 87 | count = uint8(0); 88 | while true 89 | VsfiMin = min(Vsfi,[],3); 90 | VsfYcc = rgb2ycbcr(... 91 | Vsfi - VsfiMin); 92 | %getMsf(loVdiff));%loVdiff-min(loVdiff,[],3)); 93 | %loVdiff-Saturate(loVdiffMin-mean2(loVdiffMin(:)))+mean2(Vmin(:))); 94 | VsfY = VsfYcc(:,:,1); 95 | Ymatch = imhistmatch(VsfY,VY,'Method','uniform'); 96 | % Ymatch = VsatMask.*VY + (1-VsatMask).*Ymatch; 97 | Vmatch = ycbcr2rgb(cat(3,Ymatch,VYcc(:,:,2),VYcc(:,:,3))); 98 | residual = min(1,max(0,Vsfi-Vmatch)); 99 | Vsfi = Vsfi - residual; 100 | if range(residual(:)) <= 1e-2 || count >= 8 101 | break 102 | else 103 | count = count + 1; 104 | end 105 | end 106 | spec = min(1,max(0,min(V - Vsfi,[],3))); 107 | Vdiff = V - spec; 108 | 109 | figure(2) 110 | % subplot(211),... 111 | % Show.Difference(Vsfi,V,4) 112 | % subplot(212),... 113 | Show.Difference(Vdiff,G,4) 114 | %% 115 | t = []; 116 | PSNR = zeros([80 4]); 117 | for img = 1:4 118 | V = im2double(imread(fname{img})); 119 | G = im2double(imread( gt{img})); 120 | for idx = 1:80 121 | Vavg = imgaussfilt(V,idx,'Padding','symmetric'); 122 | pSpec = min(Saturate(V-min(Vavg,[],3)),[],3); 123 | pSfi = V-pSpec; 124 | PSNR(idx,img) = psnr(pSfi,G); 125 | end 126 | end 127 | subplot(211), plot(1:80,PSNR), axis tight, grid minor,... 128 | legend({'Animals','Crups','Fruit','Masks'},'Location','southeast') 129 | subplot(212), plot(2:80,diff(PSNR)), axis tight, grid minor 130 | % Vmsf = getMsf(V); 131 | % subplot(311), Show.Difference(pSfi,V-min(V,[],3),2), title('SF v. PSFI') 132 | % subplot(312), Show.Difference(pSfi,Vmsf,2), title('MSF v. PSFI') 133 | % subplot(313), Show.Difference(pSfi,G,2), title('GT v. PSFI') 134 | 135 | %% 136 | V = im2double(imread(fname{11})); 137 | Vcorr = V; 138 | Vest = V; 139 | count = uint8(0); 140 | while true 141 | Vmsf = getMsf(V); 142 | cddts = getCandidates(V,Vmsf); 143 | m = maskAndDilateCddts(cddts,10); 144 | cddts = imbinarize(cddts); 145 | A = V; 146 | A(cddts) = 0; 147 | h = fspecial('gaussian',2*ceil(2*5)+1,5); 148 | est = imfilter(V.*(1-m),h)./imfilter(1-m,h); 149 | valid = ~isnan(est); 150 | Vcorr(valid) = V(valid).*(1-m(valid)) + est(valid).*m(valid); 151 | Vest(valid) = V(valid)-Saturate(min(V(valid)-min(Vcorr(valid),[],3),[],3)); 152 | if nnz(isnan(est)) < 1 || count >= 4 153 | break 154 | end 155 | count = count + 1; 156 | end 157 | figure, imshow(est) 158 | Show.Difference(Vest,V) 159 | %% 160 | V = im2double(imread(fname{2})); 161 | G = im2double(imread( gt{2})); 162 | Vin255 = 255*V; 163 | % filter parameters 164 | sigmaS = 32; 165 | sigmaR = 64; 166 | % call bilateral filter 167 | Vout255 = zeros(size(Vin255)); 168 | for c = 1:3 169 | Vout255(:,:,c) = shiftableBF(Vin255(:,:,c),sigmaS,sigmaR); 170 | end 171 | pSpec = min(Saturate(V-min(Vout255/255,[],3)),[],3); 172 | pSfi = V-pSpec; 173 | % figure(1), imshow(pSfi) 174 | figure(2), imshow(pSpec) 175 | figure(3), imshow(Vout255/255) 176 | figure(4), Show.Difference(pSfi,G,4) 177 | %% Functions 178 | 179 | function Vmsf = getMsf(V) 180 | %% Generate MSF 181 | % Vmsf = getMsf(V); 182 | Vmin = min(V,[],3); 183 | eta = 0.5; 184 | Tv = (mean2(Vmin(:)) + eta*std(Vmin(:))); 185 | tau = Vmin; 186 | tau(tau>Tv) = Tv; 187 | Vmsf = V - Vmin + tau; 188 | end 189 | 190 | function cddts = getCandidates(V,Vmsf) 191 | %% Get candidates 192 | % cddts = getCandidates(V,Vmsf); 193 | Vmin = min(V,[],3); 194 | th1 = mean2(Vmin(:)); 195 | cddts = ones(size(V)); 196 | cddts((V-Vmsf) LoVminEnergy 249 | % break 250 | % end 251 | % end 252 | % loVlp = ifft2(LoVlpAbs.*exp(1i*LoVang)); 253 | % vLp = imresize(loVlp,[nRow,nCol],... 254 | % 'Method','bilinear','AntiAliasing',true); 255 | % vHp = min(1,max(0,v-vLp)); 256 | % end 257 | %% 258 | % function thr = getSatThr(sat,eta) 259 | % hst = imhist(sat)/numel(sat); 260 | % cdf = cumsum(hst); 261 | % ind = find(cdf>=0.25,1); 262 | % val = (ind-1)/255; % normalize to 1 263 | % thr = mean2(sat(sat= 4 178 | % break 179 | % end 180 | % count = count + 1; 181 | % end 182 | % figure, imshow(est) 183 | % Show.Difference(Vest,V) 184 | %% 185 | % V = im2double(imread(fname{2})); 186 | % G = im2double(imread( gt{2})); 187 | % Vin255 = 255*V; 188 | % % filter parameters 189 | % sigmaS = 32; 190 | % sigmaR = 64; 191 | % % call bilateral filter 192 | % Vout255 = zeros(size(Vin255)); 193 | % for c = 1:3 194 | % Vout255(:,:,c) = shiftableBF(Vin255(:,:,c),sigmaS,sigmaR); 195 | % end 196 | % pSpec = min(Saturate(V-min(Vout255/255,[],3)),[],3); 197 | % pSfi = V-pSpec; 198 | % % figure(1), imshow(pSfi) 199 | % figure(2), imshow(pSpec) 200 | % figure(3), imshow(Vout255/255) 201 | % figure(4), Show.Difference(pSfi,G,4) 202 | 203 | %% Functions 204 | 205 | % function Vmsf = getMsf(V) 206 | % %% Generate MSF 207 | % % Vmsf = getMsf(V); 208 | % Vmin = min(V,[],3); 209 | % eta = 0.5; 210 | % Tv = (mean2(Vmin(:)) + eta*std(Vmin(:))); 211 | % tau = Vmin; 212 | % tau(tau>Tv) = Tv; 213 | % Vmsf = V - Vmin + tau; 214 | % end 215 | 216 | % function cddts = getCandidates(V,Vmsf) 217 | % %% Get candidates 218 | % % cddts = getCandidates(V,Vmsf); 219 | % Vmin = min(V,[],3); 220 | % th1 = mean2(Vmin(:)); 221 | % cddts = ones(size(V)); 222 | % cddts((V-Vmsf) LoVminEnergy 279 | % break 280 | % end 281 | % end 282 | % loVlp = ifft2(LoVlpAbs.*exp(1i*LoVang)); 283 | % vLp = imresize(loVlp,[nRow,nCol],... 284 | % 'Method','bilinear','AntiAliasing',true); 285 | % vHp = min(1,max(0,v-vLp)); 286 | % end 287 | %% 288 | % function thr = getSatThr(sat,eta) 289 | % hst = imhist(sat)/numel(sat); 290 | % cdf = cumsum(hst); 291 | % ind = find(cdf>=0.25,1); 292 | % val = (ind-1)/255; % normalize to 1 293 | % thr = mean2(sat(sat