diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/example.asv b/example.asv new file mode 100644 index 0000000..262228f --- /dev/null +++ b/example.asv @@ -0,0 +1,34 @@ +% This is an usage example of the Interactive Image Segmentation using +% Label Propagation through Complex Networks method. +% +% BREVE, Fabricio Aparecido. Interactive Image Segmentation using Label +% Propagation through Complex Networks. Expert System With Applications, +% v. 123, p.18 – 33, 2019. +% +% by Fabricio Breve - 21/01/2019 +% +% Loading example image +img = imread('ralph.jpg'); +% Loading scribbles image +imgslab = imread('ralph-scribble.png'); +% Loading ground-truth image +gt = imread('ralph-gt.png'); +% Calling method to segment the image with default parameters +disp('Running image segmentation...'); +tStart = tic; +[owner, pot] = lpcn(img, imgslab); +tElapsed = toc(tStart); +% Converting output to image +imgres = own2img(owner,img,0); +% Calculating error rate +y = imgeval(imgres, gt, imgslab); +% Displaying numerical results +fprintf('Error Rate: %0.4f - Execution Time: %0.4fs\n',y,tElapsed); +% Applying mask to the original image +imgres3 = repmat(imgres,1,1,3)./255; +imgseg = img .* imgres3; +imgseg(imgres3==0)=255; +% Showing segmentation results +subplot(2,2,1), imshow(img), +subplot(2,2,2), imshow(imgslab), +subplot(2,2,3), imshow(imgr \ No newline at end of file diff --git a/example.m b/example.m new file mode 100644 index 0000000..db1d9fc --- /dev/null +++ b/example.m @@ -0,0 +1,35 @@ +% This is an usage example of the Interactive Image Segmentation using +% Label Propagation through Complex Networks method. +% +% BREVE, Fabricio Aparecido. Interactive Image Segmentation using Label +% Propagation through Complex Networks. Expert System With Applications, +% v. 123, p.18 – 33, 2019. +% +% by Fabricio Breve - 21/01/2019 +% +% Loading example image +img = imread('ralph.jpg'); +% Loading scribbles image +imgslab = imread('ralph-scribble.png'); +% Loading ground-truth image +gt = imread('ralph-gt.png'); +% Calling method to segment the image with default parameters +disp('Running image segmentation...'); +tStart = tic; +[owner, pot] = lpcn(img, imgslab); +tElapsed = toc(tStart); +% Converting output to image +imgres = own2img(owner,img,0); +% Calculating error rate +y = imgeval(imgres, gt, imgslab); +% Displaying numerical results +fprintf('Error Rate: %0.4f - Execution Time: %0.4fs\n',y,tElapsed); +% Applying mask to the original image +imgres3 = repmat(imgres,1,1,3)./255; +imgseg = img .* imgres3; +imgseg(imgres3==0)=255; +% Showing segmentation results +subplot(2,2,1), imshow(img), +subplot(2,2,2), imshow(imgslab), +subplot(2,2,3), imshow(imgres), +subplot(2,2,4), imshow(imgseg); \ No newline at end of file diff --git a/imgeval.m b/imgeval.m new file mode 100644 index 0000000..7265053 --- /dev/null +++ b/imgeval.m @@ -0,0 +1,10 @@ +% Avaliação de imagens segmentadas do Microsoft GrabCut dataset +% Uso: error = imgeval(imgres, gt, imgslab) +% imgres - imagem resultante da segmentação +% gt - ground truth +% imgslab - imagem +function error = imgeval(imgres, gt, imgslab) + totunlpix = sum(sum(imgslab==128 & gt~=128)); + toterrpix = sum(sum(abs(double(imgres)-double(gt))>1 & imgslab==128 & gt~=128)); + error = toterrpix/totunlpix; +end \ No newline at end of file diff --git a/lpcn.asv b/lpcn.asv new file mode 100644 index 0000000..4fd8a6f --- /dev/null +++ b/lpcn.asv @@ -0,0 +1,262 @@ +% Interactive Image Segmentation using Label Propagation through Complex Networks +% by Fabricio Breve - 21/01/2019 +% +% If you use this algorithm, please cite: +% +% BREVE, Fabricio Aparecido. Interactive Image Segmentation using Label +% Propagation through Complex Networks. Expert System With Applications, +% v. 123, p.18 – 33, 2019. +% +% Usage: [owner, pot, ti1, ti2] = cnsslis9(img, imgslab, fw, k, sigma, disttype, omega, maxiter) +% +% INPUT: +% img - Image to be segmented (24 bits, 3 channels - RGB) +% imgslab - Image with labeled/unlabeled pixel information (0 is reserved +% for ignored background, 64 - background class, 128 - +% unlabeled pixels, 255 - foreground class. For multiclass use +% [1~63; 65~127; 129~254] for other classes. (Obs: use only grayscale 8-bit indexed image) +% fw - vector of feature weights +% k - each node is connected to its k-neirest neighbors +% disttype - use 'euclidean', etc. +% omega - Default: 0.001 (lower it to stop earlier, accuracy may be lower; increase to increase accuracy) +% maxiter - maximum amount of iterations +% +% OUTPUT: +% owner - vector of classes assigned to each data item +% pot - continuos-output with pertinence of each data item to each +% class +% ti1 - total iterations executed on phase 1 +% ti2 - total iterations executed on phase 2 + +function [owner, pot, ti1, ti2] = lpcn(img, imgslab, fw, k, sigma, disttype, omega, maxiter) +if (nargin < 8) || isempty(maxiter) + maxiter = 500000; % número de iterações +end +if (nargin < 7) || isempty(omega) + omega = 0.0001; +end +if (nargin < 6) || isempty(disttype) + disttype = 'euclidean'; % distância euclidiana não normalizada +end +if (nargin < 5) || isempty(sigma) + sigma = 0.5; +end +if (nargin < 4) || isempty(k) + k = 10; % quantidade de vizinhos mais próximos +end +if (nargin < 3) || isempty(fw) + fw = ones(1,9); + %fw = [1 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5]; +end +% tratamento da entrada +k = uint16(k); +ti1 = 0; +ti2 = 0; + +if k>0 + % reduzindo imagem + rs_img = imresize(img,1/3,'bicubic'); + otherlabels = [1:63 65:127 129:254]; + if isempty(intersect(unique(imgslab),otherlabels)) % se há apenas duas classes + rs_imgslab = imresize(imgslab,1/3,'bilinear'); + rs_imgslab(rs_imgslab<64 & rs_imgslab>0) = 64; + rs_imgslab(rs_imgslab<128 & rs_imgslab>64) = 64; + rs_imgslab(rs_imgslab>128) = 255; + else % mais de duas classes + rs_imgslab = imresize(imgslab,1/3,'nearest'); + end + + [rs_dim,qtnode,X,slabel,nodeval,nclass] = getFeatures(rs_img,rs_imgslab,fw); + + % já estamos normalizando de qualquer forma + if strcmp(disttype,'seuclidean')==1 + disttype='euclidean'; + end + + indval = find(nodeval); % pega só os índices dos pixels que não são do fundo ignorado + Xval = X(indval,:); % cria lista de pixels válidos (que não são do fundo ignorado) + qtnodeval = size(indval,1); % quantidade de nós válidos (pixels válidos) + slabelval = slabel(indval); % rótulos dos pixels válidos (não são do fundo ignorado) + + nnonlabeled = sum(slabelval==0); % quantidade de nós não rotulados + + % lista de nós não rotulados + indnonlabeled = uint32(find(slabelval==0)); + % lista de nós rotulados + labelednodes = uint32(find(slabelval>0)); + + % encontrando k-vizinhos mais próximos + [KNN,KNND] = knnsearch(Xval,Xval(indnonlabeled,:),'K',k+1,'NSMethod','kdtree','Distance',disttype); + KNN = uint32(KNN); + clear XVal; + KNN = KNN(:,2:end); % eliminando o elemento como vizinho de si mesmo + KNND = KNND(:,2:end); + KNND = exp((-KNND.^2)./(2*sigma^2)); + % ajustando todas as distâncias na máxima possível + potval = repmat(1/nclass,qtnodeval,nclass); + % zerando potenciais dos nós rotulados + potval(labelednodes,:) = 0; + % ajustando potencial da classe respectiva do nó rotulado para máximo + potval(sub2ind(size(potval),labelednodes,slabelval(labelednodes))) = 1; + % calling the mex function + ti1 = lpcnloop(maxiter,nnonlabeled,indnonlabeled,omega,potval,k,KNN,KNND); + + clear KNN slabelval KNNND; + + pot = zeros(qtnode,nclass); + pot(:,1) = 1; % nós de fundo serão associados à mesma classe da cor de índice 64. + pot(indval,:)=potval; + + clear potval; +end + +[dim,qtnode,X,slabel,nodeval,nclass] = getFeatures(img,imgslab,fw); +% Redimensionar matriz de potenciais +% (antes de redimensionar é preciso passar para matriz de 3 dimensões e +% depois voltar para o formato anterior) +if k>0 + pot = reshape(imresize(reshape(pot,rs_dim(1),rs_dim(2),nclass),[dim(1) dim(2)],'bilinear'),qtnode,nclass); +else + pot = repmat(1/nclass,qtnode,nclass); +end + +% encontrando nos rotulados +labelednodes = find(slabel>0); +% zerando potenciais dos nós rotulados +pot(labelednodes,:) = 0; +% ajustando potencial da classe respectiva do nó rotulado para 1 +pot(sub2ind(size(pot),labelednodes,slabel(labelednodes))) = 1; + +% PARTE 2! +%disp('Parte 2: Encontrando vizinhos...'); +if k>0 + indefnodesb = max(pot,[],2) < 1; % vetor onde 1 é nó indefinido e 0 é definido +else + indefnodesb = nodeval; % dessa forma todos os vetores de dominância ficam variáveis e a propagação ocorre entre todos os pixels. Por algum motivo isso funciona melhor na base da Microsoft. +end +indefnodes = uint32(find(indefnodesb)); % lista de nós indefinidos +indefnodesc = size(indefnodes,1); % contagem de nós indefinidos + +if indefnodesc>0 + + %fprintf('Parte 2: %i nós indefinidos. Pegando colaboração de pixels vizinhos\n',size(indefnodes,1)) + + Ndist = zeros(size(X,1),8); + Nlist = zeros(size(X,1),8,'uint32'); + Nsize = zeros(size(X,1),1,'uint8'); + % Pesos das ligações horizontais + for i=1:dim(1) + for j=1:dim(2)-1 + ind1 = i+(j-1)*dim(1); + ind2 = ind1 + dim(1); + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + % Peso das ligações diagonais (\) + for i=1:dim(1)-1 + for j=1:dim(2)-1 + ind1 = i+(j-1)*dim(1); + ind2 = ind1+dim(1)+1; + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + % Peso das ligações verticais + for i=1:dim(1)-1 + for j=1:dim(2) + ind1 = i+(j-1)*dim(1); + ind2 = ind1+1; + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + % Peso das ligações diagonais (/) + for i=1:dim(1)-1 + for j=2:dim(2) + ind1 = i+(j-1)*dim(1); + ind2 = ind1-dim(1)+1; + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + clear X; + % aplicando Gaussiana nas distâncias + Ndist = exp((-Ndist.^2)./(2*sigma^2)); + % constantes + npart = indefnodesc; % quantidade de nós ainda não rotulados + % variável para guardar máximo potencial mais alto médio + % chamando o arquivo mex do strwalk25 + %disp('Parte 2: Propagação de rótulos...'); + ti2 = lpccnsslis9loop2(maxiter, npart, nclass, omega, indefnodes, slabel, Nsize, Nlist, Ndist, pot); + + if k==0 + % zerando potenciais dos nós rotulados + pot(labelednodes,:) = 0; + % ajustando potencial da classe respectiva do nó rotulado para 1 + pot(sub2ind(size(pot),labelednodes,slabel(labelednodes))) = 1; + end + +end +[~,owner] = max(pot,[],2); + + function p2addNeighbor + Nsize(ind1) = Nsize(ind1) + 1; + Nsize(ind2) = Nsize(ind2) + 1; + Ndist(ind1,Nsize(ind1)) = norm(X(ind1,:)-X(ind2,:)); + Ndist(ind2,Nsize(ind2)) = Ndist(ind1,Nsize(ind1)); + Nlist(ind1,Nsize(ind1)) = ind2; + Nlist(ind2,Nsize(ind2)) = ind1; + end + +end + +function [dim,qtnode,X,slabel,nodeval,nclass] = getFeatures(img,imgslab,fw) + +% Atenção: Atributo Linha e HSV estão errados em todas as versões anteriores deste algoritmo! + +% Dimensões da imagem +dim = size(img); +qtnode = dim(1)*dim(2); +X = zeros(qtnode,9); +% primeiro e segundo elementos são linha e coluna normalizadas no intervalo 0:1 +X(:,1:2) = [repmat(((1:dim(1))/dim(1))',dim(2),1), reshape(repmat((1:dim(1))/dim(1),dim(2),1),dim(1)*dim(2),1)]; +% depois vem os 3 elementos RGB normalizados em 0:1 +imgvec = double(squeeze(reshape(img,dim(1)*dim(2),1,3)))/255; +X(:,3:5) = imgvec; +% depois vem os 3 elementos HSV +imghsv = rgb2hsv(double(img)/255); +X(:,6) = squeeze(reshape(imghsv(:,:,3),dim(1)*dim(2),1,1)); +% em seguida ExR, ExG, e ExB +exr = 2.*double(img(:,:,1)) - double(img(:,:,2)) - double(img(:,:,3)); +exg = 2.*double(img(:,:,2)) - double(img(:,:,1)) - double(img(:,:,3)); +exb = 2.*double(img(:,:,3)) - double(img(:,:,1)) - double(img(:,:,2)); +imgex = cat(3, exr, exg, exb); +clear exr exg exb; +X(:,7:9) = squeeze(reshape(imgex,dim(1)*dim(2),1,3)); +X = zscore(X) .* repmat(fw,qtnode,1); +% Converter imagem com rótulos em vetor de rótulos +slabelraw = reshape(imgslab,dim(1)*dim(2),1); +% montar vetor onde 0 é nó do fundo não considerado e 1 é nó válido +nodeval = zeros(qtnode,1); +nodeval(slabelraw~=0)=1; +% ajustar vetor de rótulos +slabel = zeros(qtnode,1,'uint16'); +slabel(slabelraw==0)=1; % fundo não considerado +slabel(slabelraw==64)=1; % c/ rótulo - fundo +otherlabels = [1:63 65:127 129:254]; +olfound = intersect(unique(slabelraw),otherlabels); +if isempty(olfound) % se não outros rótulos, i.e., há apenas duas classes + nclass=2; +else % se há mais rótulos + nclass=size(olfound,1)+2; + for i=1:nclass-2 + slabel(slabelraw==olfound(i)) = i+1; + end +end +slabel(slabelraw==255)=nclass; % c/ rótulo - objeto +end \ No newline at end of file diff --git a/lpcn.m b/lpcn.m new file mode 100644 index 0000000..aa30239 --- /dev/null +++ b/lpcn.m @@ -0,0 +1,262 @@ +% Interactive Image Segmentation using Label Propagation through Complex Networks +% by Fabricio Breve - 21/01/2019 +% +% If you use this algorithm, please cite: +% +% BREVE, Fabricio Aparecido. Interactive Image Segmentation using Label +% Propagation through Complex Networks. Expert System With Applications, +% v. 123, p.18 – 33, 2019. +% +% Usage: [owner, pot, ti1, ti2] = cnsslis9(img, imgslab, fw, k, sigma, disttype, omega, maxiter) +% +% INPUT: +% img - Image to be segmented (24 bits, 3 channels - RGB) +% imgslab - Image with labeled/unlabeled pixel information (0 is reserved +% for ignored background, 64 - background class, 128 - +% unlabeled pixels, 255 - foreground class. For multiclass use +% [1~63; 65~127; 129~254] for other classes. (Obs: use only grayscale 8-bit indexed image) +% fw - vector of feature weights +% k - each node is connected to its k-neirest neighbors +% disttype - use 'euclidean', etc. +% omega - Default: 0.001 (lower it to stop earlier, accuracy may be lower; increase to increase accuracy) +% maxiter - maximum amount of iterations +% +% OUTPUT: +% owner - vector of classes assigned to each data item +% pot - continuos-output with pertinence of each data item to each +% class +% ti1 - total iterations executed on phase 1 +% ti2 - total iterations executed on phase 2 + +function [owner, pot, ti1, ti2] = lpcn(img, imgslab, fw, k, sigma, disttype, omega, maxiter) +if (nargin < 8) || isempty(maxiter) + maxiter = 500000; % número de iterações +end +if (nargin < 7) || isempty(omega) + omega = 0.0001; +end +if (nargin < 6) || isempty(disttype) + disttype = 'euclidean'; % distância euclidiana não normalizada +end +if (nargin < 5) || isempty(sigma) + sigma = 0.5; +end +if (nargin < 4) || isempty(k) + k = 10; % quantidade de vizinhos mais próximos +end +if (nargin < 3) || isempty(fw) + fw = ones(1,9); + %fw = [1 1 0.5 0.5 0.5 0.5 0.5 0.5 0.5]; +end +% tratamento da entrada +k = uint16(k); +ti1 = 0; +ti2 = 0; + +if k>0 + % reduzindo imagem + rs_img = imresize(img,1/3,'bicubic'); + otherlabels = [1:63 65:127 129:254]; + if isempty(intersect(unique(imgslab),otherlabels)) % se há apenas duas classes + rs_imgslab = imresize(imgslab,1/3,'bilinear'); + rs_imgslab(rs_imgslab<64 & rs_imgslab>0) = 64; + rs_imgslab(rs_imgslab<128 & rs_imgslab>64) = 64; + rs_imgslab(rs_imgslab>128) = 255; + else % mais de duas classes + rs_imgslab = imresize(imgslab,1/3,'nearest'); + end + + [rs_dim,qtnode,X,slabel,nodeval,nclass] = getFeatures(rs_img,rs_imgslab,fw); + + % já estamos normalizando de qualquer forma + if strcmp(disttype,'seuclidean')==1 + disttype='euclidean'; + end + + indval = find(nodeval); % pega só os índices dos pixels que não são do fundo ignorado + Xval = X(indval,:); % cria lista de pixels válidos (que não são do fundo ignorado) + qtnodeval = size(indval,1); % quantidade de nós válidos (pixels válidos) + slabelval = slabel(indval); % rótulos dos pixels válidos (não são do fundo ignorado) + + nnonlabeled = sum(slabelval==0); % quantidade de nós não rotulados + + % lista de nós não rotulados + indnonlabeled = uint32(find(slabelval==0)); + % lista de nós rotulados + labelednodes = uint32(find(slabelval>0)); + + % encontrando k-vizinhos mais próximos + [KNN,KNND] = knnsearch(Xval,Xval(indnonlabeled,:),'K',k+1,'NSMethod','kdtree','Distance',disttype); + KNN = uint32(KNN); + clear XVal; + KNN = KNN(:,2:end); % eliminando o elemento como vizinho de si mesmo + KNND = KNND(:,2:end); + KNND = exp((-KNND.^2)./(2*sigma^2)); + % ajustando todas as distâncias na máxima possível + potval = repmat(1/nclass,qtnodeval,nclass); + % zerando potenciais dos nós rotulados + potval(labelednodes,:) = 0; + % ajustando potencial da classe respectiva do nó rotulado para máximo + potval(sub2ind(size(potval),labelednodes,slabelval(labelednodes))) = 1; + % calling the mex function + ti1 = lpcnloop(maxiter,nnonlabeled,indnonlabeled,omega,potval,k,KNN,KNND); + + clear KNN slabelval KNNND; + + pot = zeros(qtnode,nclass); + pot(:,1) = 1; % nós de fundo serão associados à mesma classe da cor de índice 64. + pot(indval,:)=potval; + + clear potval; +end + +[dim,qtnode,X,slabel,nodeval,nclass] = getFeatures(img,imgslab,fw); +% Redimensionar matriz de potenciais +% (antes de redimensionar é preciso passar para matriz de 3 dimensões e +% depois voltar para o formato anterior) +if k>0 + pot = reshape(imresize(reshape(pot,rs_dim(1),rs_dim(2),nclass),[dim(1) dim(2)],'bilinear'),qtnode,nclass); +else + pot = repmat(1/nclass,qtnode,nclass); +end + +% encontrando nos rotulados +labelednodes = find(slabel>0); +% zerando potenciais dos nós rotulados +pot(labelednodes,:) = 0; +% ajustando potencial da classe respectiva do nó rotulado para 1 +pot(sub2ind(size(pot),labelednodes,slabel(labelednodes))) = 1; + +% PARTE 2! +%disp('Parte 2: Encontrando vizinhos...'); +if k>0 + indefnodesb = max(pot,[],2) < 1; % vetor onde 1 é nó indefinido e 0 é definido +else + indefnodesb = nodeval; % dessa forma todos os vetores de dominância ficam variáveis e a propagação ocorre entre todos os pixels. Por algum motivo isso funciona melhor na base da Microsoft. +end +indefnodes = uint32(find(indefnodesb)); % lista de nós indefinidos +indefnodesc = size(indefnodes,1); % contagem de nós indefinidos + +if indefnodesc>0 + + %fprintf('Parte 2: %i nós indefinidos. Pegando colaboração de pixels vizinhos\n',size(indefnodes,1)) + + Ndist = zeros(size(X,1),8); + Nlist = zeros(size(X,1),8,'uint32'); + Nsize = zeros(size(X,1),1,'uint8'); + % Pesos das ligações horizontais + for i=1:dim(1) + for j=1:dim(2)-1 + ind1 = i+(j-1)*dim(1); + ind2 = ind1 + dim(1); + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + % Peso das ligações diagonais (\) + for i=1:dim(1)-1 + for j=1:dim(2)-1 + ind1 = i+(j-1)*dim(1); + ind2 = ind1+dim(1)+1; + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + % Peso das ligações verticais + for i=1:dim(1)-1 + for j=1:dim(2) + ind1 = i+(j-1)*dim(1); + ind2 = ind1+1; + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + % Peso das ligações diagonais (/) + for i=1:dim(1)-1 + for j=2:dim(2) + ind1 = i+(j-1)*dim(1); + ind2 = ind1-dim(1)+1; + if indefnodesb(ind1) || indefnodesb(ind2) + p2addNeighbor; + end + end + end + clear X; + % aplicando Gaussiana nas distâncias + Ndist = exp((-Ndist.^2)./(2*sigma^2)); + % constantes + npart = indefnodesc; % quantidade de nós ainda não rotulados + % variável para guardar máximo potencial mais alto médio + % chamando o arquivo mex do strwalk25 + %disp('Parte 2: Propagação de rótulos...'); + ti2 = lpcnloop2(maxiter, npart, nclass, omega, indefnodes, slabel, Nsize, Nlist, Ndist, pot); + + if k==0 + % zerando potenciais dos nós rotulados + pot(labelednodes,:) = 0; + % ajustando potencial da classe respectiva do nó rotulado para 1 + pot(sub2ind(size(pot),labelednodes,slabel(labelednodes))) = 1; + end + +end +[~,owner] = max(pot,[],2); + + function p2addNeighbor + Nsize(ind1) = Nsize(ind1) + 1; + Nsize(ind2) = Nsize(ind2) + 1; + Ndist(ind1,Nsize(ind1)) = norm(X(ind1,:)-X(ind2,:)); + Ndist(ind2,Nsize(ind2)) = Ndist(ind1,Nsize(ind1)); + Nlist(ind1,Nsize(ind1)) = ind2; + Nlist(ind2,Nsize(ind2)) = ind1; + end + +end + +function [dim,qtnode,X,slabel,nodeval,nclass] = getFeatures(img,imgslab,fw) + +% Atenção: Atributo Linha e HSV estão errados em todas as versões anteriores deste algoritmo! + +% Dimensões da imagem +dim = size(img); +qtnode = dim(1)*dim(2); +X = zeros(qtnode,9); +% primeiro e segundo elementos são linha e coluna normalizadas no intervalo 0:1 +X(:,1:2) = [repmat(((1:dim(1))/dim(1))',dim(2),1), reshape(repmat((1:dim(1))/dim(1),dim(2),1),dim(1)*dim(2),1)]; +% depois vem os 3 elementos RGB normalizados em 0:1 +imgvec = double(squeeze(reshape(img,dim(1)*dim(2),1,3)))/255; +X(:,3:5) = imgvec; +% depois vem os 3 elementos HSV +imghsv = rgb2hsv(double(img)/255); +X(:,6) = squeeze(reshape(imghsv(:,:,3),dim(1)*dim(2),1,1)); +% em seguida ExR, ExG, e ExB +exr = 2.*double(img(:,:,1)) - double(img(:,:,2)) - double(img(:,:,3)); +exg = 2.*double(img(:,:,2)) - double(img(:,:,1)) - double(img(:,:,3)); +exb = 2.*double(img(:,:,3)) - double(img(:,:,1)) - double(img(:,:,2)); +imgex = cat(3, exr, exg, exb); +clear exr exg exb; +X(:,7:9) = squeeze(reshape(imgex,dim(1)*dim(2),1,3)); +X = zscore(X) .* repmat(fw,qtnode,1); +% Converter imagem com rótulos em vetor de rótulos +slabelraw = reshape(imgslab,dim(1)*dim(2),1); +% montar vetor onde 0 é nó do fundo não considerado e 1 é nó válido +nodeval = zeros(qtnode,1); +nodeval(slabelraw~=0)=1; +% ajustar vetor de rótulos +slabel = zeros(qtnode,1,'uint16'); +slabel(slabelraw==0)=1; % fundo não considerado +slabel(slabelraw==64)=1; % c/ rótulo - fundo +otherlabels = [1:63 65:127 129:254]; +olfound = intersect(unique(slabelraw),otherlabels); +if isempty(olfound) % se não outros rótulos, i.e., há apenas duas classes + nclass=2; +else % se há mais rótulos + nclass=size(olfound,1)+2; + for i=1:nclass-2 + slabel(slabelraw==olfound(i)) = i+1; + end +end +slabel(slabelraw==255)=nclass; % c/ rótulo - objeto +end \ No newline at end of file diff --git a/lpcnloop.c b/lpcnloop.c new file mode 100644 index 0000000..4058ba6 --- /dev/null +++ b/lpcnloop.c @@ -0,0 +1,124 @@ +#include +#include "mex.h" + +/* Input Arguments */ + +#define maxiter_IN prhs[0] +#define nnonlabeled_IN prhs[1] +#define indnonlabeled_IN prhs[2] +#define omega_IN prhs[3] +#define potval_IN prhs[4] +#define k_IN prhs[5] +#define nlist_IN prhs[6] +#define ndist_IN prhs[7] + +/* Output Arguments */ + +#define ph1_ttiter_OUT plhs[0] + +void mexFunction( int nlhs, mxArray *plhs[], + int nrhs, const mxArray*prhs[] ) + +{ + int maxiter, nnonlabeled; // escalares int + unsigned short int k; // escalar de uint16 + unsigned int *indnonlabeled, *nlist; // vetores de uint32 + double *potval, *ndist; // matrizes de double + int qtnode, nclass; + double omega; + + /* Check for proper number of arguments */ + + + if (nrhs != 8) { + mexErrMsgTxt("8 argumentos de entrada requeridos."); + } else if (nlhs > 1) { + mexErrMsgTxt("Only 1 output argument allowed."); + } + + maxiter = (int) mxGetScalar(maxiter_IN); + nnonlabeled = (int) mxGetScalar(nnonlabeled_IN); + indnonlabeled = (unsigned int *) mxGetData(indnonlabeled_IN); + omega = mxGetScalar(omega_IN); + k = (unsigned short int) mxGetScalar(k_IN); + nlist = (unsigned int *) mxGetData(nlist_IN); + potval = mxGetPr(potval_IN); + ndist = mxGetPr(ndist_IN); + + qtnode = (int) mxGetM(potval_IN); + nclass = (int) mxGetN(potval_IN); + + double maxmmpot = 0; + double *newpot = malloc(sizeof(double) * nnonlabeled * nclass); + int i; + for(i=0; impot) mpot = potval[ppj + qtnode*i3]; + // e então somá-lo + mmpot += mpot; + } + // e por fim dividir pela quantidade de nós para obter a média + mmpot /= nnonlabeled; + + //printf("Iter: %i Meanpot: %0.4f\n",i,mmpot); + // se da última maior média para a atual aumentou mais que 0.001 + if (mmpot - maxmmpot > omega) maxmmpot = mmpot; + else break; + } + } + + free(newpot); + + ph1_ttiter_OUT = mxCreateDoubleScalar(i); + return; + +} diff --git a/lpcnloop.mexw64 b/lpcnloop.mexw64 new file mode 100644 index 0000000..903aa25 Binary files /dev/null and b/lpcnloop.mexw64 differ diff --git a/lpcnloop2.c b/lpcnloop2.c new file mode 100644 index 0000000..48edc81 --- /dev/null +++ b/lpcnloop2.c @@ -0,0 +1,123 @@ +#include +#include "mex.h" + +/* Input Arguments */ + +#define maxiter_IN prhs[0] +#define npart_IN prhs[1] +#define nclass_IN prhs[2] +#define omega_IN prhs[3] +#define partnode_IN prhs[4] +#define slabel_IN prhs[5] +#define nsize_IN prhs[6] +#define nlist_IN prhs[7] +#define ndist_IN prhs[8] +#define pot_IN prhs[9] + +/* Output Arguments */ + +#define ph2_ttiter_OUT plhs[0] + +void mexFunction( int nlhs, mxArray *plhs[], + int nrhs, const mxArray*prhs[] ) +{ + int maxiter, npart, nclass; // escalares int + unsigned int *partnode; + unsigned char *nsize; + unsigned short int *slabel; + unsigned int *nlist; // matrizes de int + double *ndist, *pot; // matrizes de double + int qtnode, neibmax; + double omega; + + /* Check for proper number of arguments */ + + + if (nrhs != 10) { + mexErrMsgTxt("10 argumentos de entrada requeridos."); + } else if (nlhs > 1) { + mexErrMsgTxt("Only 1 output argument allowed."); + } + + maxiter = (int) mxGetScalar(maxiter_IN); + npart = (int) mxGetScalar(npart_IN); + nclass = (int) mxGetScalar(nclass_IN); + omega = mxGetScalar(omega_IN); + partnode = (unsigned int *) mxGetData(partnode_IN); + slabel = (unsigned short int *) mxGetData(slabel_IN); + nsize = (unsigned char *) mxGetData(nsize_IN); + nlist = (unsigned int *) mxGetData(nlist_IN); + ndist = mxGetPr(ndist_IN); + pot = mxGetPr(pot_IN); + + qtnode = (int) mxGetM(slabel_IN); + neibmax = (int) mxGetN(nlist_IN); // quantidade máxima de vizinhos que um nó tem + + // non-Windows users should probably use /dev/random or /dev/urandom instead of rand_s + //unsigned int seed; + //errno_t err; + //err = rand_s(&seed); + //if (err != 0) printf_s("The rand_s function failed!\n"); + //srand(seed); + double maxmmpot = 0; + double *prob = malloc(sizeof(double)*neibmax); // vetor de probabilidades de visitar vizinho + double *nc = malloc(sizeof(double)*nclass); + double *newpot = malloc(sizeof(double)*qtnode*nclass); + for(int i=0; impot) mpot = pot[i3*qtnode + i2]; + mmpot += mpot; + } + mmpot /= qtnode; + +// if (i % 10000 == 0) +// { +// printf("Iter: %i Meanpot: %0.4f\n",i,mmpot); +// mexEvalString("drawnow"); +// } + + if (mmpot - maxmmpot > omega) maxmmpot = mmpot; + else break; + } + } + free(prob); + free(nc); + free(newpot); + free(labeled); + + ph2_ttiter_OUT = mxCreateDoubleScalar(i); + + return; +} diff --git a/lpcnloop2.mexw64 b/lpcnloop2.mexw64 new file mode 100644 index 0000000..8dce474 Binary files /dev/null and b/lpcnloop2.mexw64 differ diff --git a/own2img.m b/own2img.m new file mode 100644 index 0000000..fa65a32 --- /dev/null +++ b/own2img.m @@ -0,0 +1,20 @@ +%Uso: own2img(owner,img,1) - exibe imagem +% imgres = own2img(owner,img,0); - não exibe imagem +function imgres = own2img(owner,img,exhibitimg,imgslab) +if (nargin < 3) || isempty(exhibitimg) + exhibitimg = 1; +end +dim = size(img); +if (nargin <4) || isempty(imgslab) + owner = owner-min(owner); + owner = owner./max(owner)*255; +else + colors = unique(imgslab); + colors = [0; colors(colors~=64 & colors~=128)]; + owner = colors(owner); +end +imgres = uint8(reshape(owner,dim(1),dim(2))); +if exhibitimg==1 + imshow(imgres,gray(256)) +end +end \ No newline at end of file diff --git a/ralph-gt.png b/ralph-gt.png new file mode 100644 index 0000000..c6821e5 Binary files /dev/null and b/ralph-gt.png differ diff --git a/ralph-scribble.png b/ralph-scribble.png new file mode 100644 index 0000000..c457d78 Binary files /dev/null and b/ralph-scribble.png differ diff --git a/ralph-scribblemix.jpg b/ralph-scribblemix.jpg new file mode 100644 index 0000000..c43b60e Binary files /dev/null and b/ralph-scribblemix.jpg differ diff --git a/ralph.jpg b/ralph.jpg new file mode 100644 index 0000000..7c26d45 Binary files /dev/null and b/ralph.jpg differ