function varargout = hyperactive(varargin)
% hyperactive -- Hyperspectral image classification GUI
% Written by Meiching Fong, Zhong Hu, & Todd Wittman
% UCLA Math, 2007
% Uses routines in Image Processing & Statistics Toolbox
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @hyperactive_OpeningFcn, ...
                   'gui_OutputFcn',  @hyperactive_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before hyperactive is made visible.
function hyperactive_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to hyperactive (see VARARGIN)
% Choose default command line output for hyperactive
handles.output = hObject;
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes hyperactive wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = hyperactive_OutputFcn(hObject, eventdata, handles) 
varargout{1} = handles.output;



function PictureEdit1_Callback(hObject, eventdata, handles)



% --- Executes during object creation, after setting all properties.
function PictureEdit1_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in LoadButton1.
function LoadButton1_Callback(hObject, eventdata, handles)
filename=get(handles.PictureEdit1,'string');
%A=imread(filename);
handles.A=evalin('base',filename);
axes(handles.axes1);
x=get(handles.bandslider1,'value');
[n1,n2,N]=size(handles.A);
set(handles.bandslider1,'SliderStep',[(1/N),0.1]);
j=round((N-1)*x+1);
imagesc(handles.A(:,:,j));  
s = get(handles.ColorMap,'string');
colormap(s{get(handles.ColorMap,'Value')});
set(handles.bandnumber,'string',['Band ',num2str(j),' of ',num2str(N)]);
%colorbar;
guidata(hObject,handles);



% --- Executes on selection change in ColorMap.
function ColorMap_Callback(hObject, eventdata, handles)
axes(handles.axes1);
s = get(handles.ColorMap,'string');
colormap(s{get(handles.ColorMap,'Value')});



% --- Executes during object creation, after setting all properties.
function ColorMap_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on slider movement.
function bandslider1_Callback(hObject, eventdata, handles)
axes(handles.axes1);
x=get(handles.bandslider1,'value');
[n1,n2,N]=size(handles.A);
j=round((N-1)*x+1);
imagesc(handles.A(:,:,j));
s = get(handles.ColorMap,'string');
colormap(s{get(handles.ColorMap,'Value')});
set(handles.bandnumber,'string',['Band ',num2str(j),' of ',num2str(N)]);
guidata(hObject,handles);




% --- Executes during object creation, after setting all properties.
function bandslider1_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end





function Numberclusters_Callback(hObject, eventdata, handles)



% --- Executes during object creation, after setting all properties.
function Numberclusters_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in Loadbutton2.
function Loadbutton2_Callback(hObject, eventdata, handles)
axes(handles.axes1);
x=get(handles.bandslider1,'value');
[n1,n2,N]=size(handles.A);
j=round((N-1)*x+1);
imagesc(handles.A(:,:,j));  
tic;
set(handles.runningtime,'string','Busy');
drawnow;
k=str2num(get(handles.Numberclusters,'string'));

%Run the chosen clustering method.
menuString = get(handles.Distance,'string');
distString = menuString{get(handles.Distance,'value')};
NK = 50;   %Number of preliminary clusters for agglomerative clustering.
if get(handles.checkspatial,'value')==1
   lambda=str2num(get(handles.weight,'string'));
   X=ones(n1,1)*(1:n2);
   Y=[1:n1]'*ones(1,n2);
   handles.A(:,:,N+1)=lambda*X;
   handles.A(:,:,N+2)=lambda*Y;
   N=N+2;
   guidata(hObject,handles);
end
if get(handles.Clustermenu,'value')==1 %Kmeans
    B=reshape(handles.A,[n1*n2,N]);
    try 
        C=kmeans(B,k,'Distance',distString);
        [x,y,z] = size(handles.A);
        handles.C = reshape(C,[x,y]);
        set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
    catch
       set(handles.runningtime,'String','Kmeans failed.  Bummer.');
    end

elseif get(handles.Clustermenu,'value')==2 %NearestNeighbor
    handles.C = NearestNeighbor(handles,hObject);
elseif get(handles.Clustermenu,'value')==3  %Agglom (group average)
    B=reshape(handles.A,[n1*n2,N]);
    C = clusterdata(B,'distance',distString,'linkage','average','maxclust',k);
    [x,y,z] = size(handles.A);
    handles.C = reshape(C,[x,y]);
    set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
elseif get(handles.Clustermenu,'value')==4  %Agglom (min)
    B=reshape(handles.A,[n1*n2,N]);
    %     [Ckmeans, mu] = kmeans(B,NK,'Distance','sqEuclidean');
    %     D = clusterdata(mu,'distance',distString,'linkage','single','maxclust',k);
    %     C = zeros(size(B));
    %     for i = 1:NK
    %         C = C + D(i)*[Ckmeans == i];  
    %     end;
    C = clusterdata(B,'distance',distString,'linkage','single','maxclust',k);
    [x,y,z] = size(handles.A);
    handles.C = reshape(C,[x,y]);
    set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
elseif get(handles.Clustermenu,'value')==5  %Agglom (max)
    B=reshape(handles.A,[n1*n2,N]);
    C = clusterdata(B,'distance',distString,'linkage','complete','maxclust',k);
    [x,y,z] = size(handles.A);
    handles.C = reshape(C,[x,y]);
    set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
elseif get(handles.Clustermenu,'value')==6  %Agglom (Ward's Method)
    B=reshape(handles.A,[n1*n2,N]);
    C = clusterdata(B,'distance',distString,'linkage','ward','maxclust',k);
    [x,y,z] = size(handles.A);
    handles.C = reshape(C,[x,y]);
    set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
end;
if get(handles.checkspatial,'value')==1
   B=handles.A(:,:,[1:N-2]);
   clear handles.A;
   handles.A=B;
end

[x,y,z]=size(handles.A);
axes(handles.axes2);
imagesc(handles.C);
guidata(hObject,handles);


function [C] = NearestNeighbor(handles,hObject)
s = get(handles.ColorMap,'string');
axes(handles.axes1);
[m,n,d]=size(handles.A);
k=str2num(get(handles.Numberclusters,'string'));
for i=1:k
    set(handles.runningtime,'string',['Click on point #',num2str(i)]);
    P(i,:)=round(ginput(1));
    hold on;
    scatter(P(i,1),P(i,2),'r');
    drawnow;
    hold off;
end
%Just for testing for Nearest Neighbor.
%P=[212,110;180,30;139,281;136,175]; 
set(handles.runningtime,'string',['Running Nearest Neighbor...']);
drawnow;
tic;
B=reshape(handles.A,[m*n,d]);
for i=1:k    
    r(i,:)=handles.A(P(i,2),P(i,1),:);
    R=ones(m*n,1)*r(i,:);
    if get(handles.Distance,'value')==1  %Euclidean
        D(:,i)=sum( (R-B).^2,2);
    elseif get(handles.Distance,'value')==2  %L1-Norm
        D(:,i)=sum(abs(R-B),2);
    elseif get(handles.Distance,'value')==3  %Cosine
        D(:,i)=1-sum(R.*B,2)./(sqrt(sum(R.^2,2)).*sqrt(sum(B.^2,2))+eps);
    elseif get(handles.Distance,'value')==4   %Correlation
        meanR=sum(R,2)*ones(1,d)/d;
        meanB=sum(B,2)*ones(1,d)/d;
        D(:,i)=1-sum((R-meanR).*(B-meanB),2)./(sqrt(sum((R-meanR).^2,2)).*sqrt(sum((B-meanB).^2,2))+eps);
    end
end
[d,c]=min(D,[],2);
axes(handles.axes2);
C=reshape(c',[m,n]);
set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
drawnow;
guidata(hObject,handles);




% --- Executes on selection change in Clustermenu.
function Clustermenu_Callback(hObject, eventdata, handles)
warning off;
set(handles.Distance,'value',1);
if get(handles.Clustermenu,'value') == 1    %K-means
    distString{1} = 'sqEuclidean';
    distString{2} = 'cityblock';
    distString{3} = 'cosine';
    distString{4} = 'correlation';
    distString{5} = 'hamming';
    set(handles.Distance,'string',distString);
elseif get(handles.Clustermenu,'value') == 2  %Nearest Neighbor
    distString{1} = 'Euclidean';
    distString{2} = 'L1-Norm';
    distString{3} = 'cosine';
    distString{4} = 'correlation';
    set(handles.Distance,'string',distString);
elseif (get(handles.Clustermenu,'value') == 3 ... 
        || get(handles.Clustermenu,'value') == 4 ...
        || get(handles.Clustermenu,'value') == 5 ... 
        || get(handles.Clustermenu,'value') == 6)     % Agglomerative Clustering
    distString{1} = 'euclidean';
    distString{2} = 'seuclidean';
    distString{3} = 'mahalonobis';
    distString{4} = 'cityblock';
    distString{5} = 'minkowski';
    distString{6} = 'cosine';
    distString{7} = 'correlation';
    distString{8} = 'spearman';
    distString{9} = 'hamming';
    distString{10} = 'jaccard';
    distString{11} = 'chebychev';
    set(handles.Distance,'string',distString);
end;
guidata(hObject,handles);
warning on;



% --- Executes during object creation, after setting all properties.
function Clustermenu_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end




% --- Executes on selection change in Distance.
function Distance_Callback(hObject, eventdata, handles)


% --- Executes during object creation, after setting all properties.
function Distance_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end






% --- Executes on button press in delete.
function delete_Callback(hObject, eventdata, handles)
axes(handles.axes1);
x=get(handles.bandslider1,'value');
[n1,n2,N]=size(handles.A);
j=round((N-1)*x+1);
B=handles.A(:,:,[1:j-1,j+1:N]);
clear handles.A;
handles.A=B;
guidata(hObject,handles);
x=get(handles.bandslider1,'value');
[n1,n2,N]=size(handles.A);
set(handles.bandslider1,'SliderStep',[(1/N),0.1]);
j=round((N-1)*x+1);
imagesc(handles.A(:,:,j));
s = get(handles.ColorMap,'string');
colormap(s{get(handles.ColorMap,'Value')});
set(handles.bandnumber,'string',['Band ',num2str(j),' of ',num2str(N)]);
guidata(hObject,handles);




% --- Executes on button press in PCAbutton.
function PCAbutton_Callback(hObject, eventdata, handles)
set(handles.runningtime,'string',['Running PCA...']);
drawnow;
tic;
[m,n,d] = size(handles.A);
dim = str2num(get(handles.dim_edit,'string'));
B = reshape(handles.A,[m*n,d]);
[res,R] = pcares(B,dim);
clear handles.A;
handles.A = reshape(R(:,1:dim),[m,n,dim]);
set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
bandslider1_Callback(hObject, eventdata, handles);
guidata(hObject,handles);



function dim_edit_Callback(hObject, eventdata, handles)



% --- Executes during object creation, after setting all properties.
function dim_edit_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in smooth_nei.
function smooth_nei_Callback(hObject, eventdata, handles)
tic;
set(handles.runningtime,'String','Running 3x3 Mode Filter...');
drawnow;
[m,n] = size(handles.C);
X(:,:,1) = handles.C(2:m-1,2:n-1);
X(:,:,2) = handles.C(1:m-2,1:n-2);
X(:,:,3) = handles.C(1:m-2,2:n-1);
X(:,:,4) = handles.C(1:m-2,3:n);
X(:,:,5) = handles.C(2:m-1,1:n-2);
X(:,:,6) = handles.C(2:m-1,3:n);
X(:,:,7) = handles.C(3:m,1:n-2);
X(:,:,8) = handles.C(3:m,2:n-1);
X(:,:,9) = handles.C(3:m,3:n);
maxVal = mode(X,3);
handles.C(2:m-1,2:n-1) = maxVal;
axes(handles.axes2);
imagesc(handles.C);
set(handles.runningtime,'string',['runtime = ',num2str(toc),'sec']);
guidata(hObject,handles);




% --- Executes on button press in GT_load.
function GT_load_Callback(hObject, eventdata, handles)
load Urban;
axes(handles.axes3);
imagesc(M);


% --- Executes on button press in compute_error.
function compute_error_Callback(hObject, eventdata, handles)
load Urban M;
axes(handles.axes3);
imagesc(M);
P=perms(1:4);
C1=[handles.C==1];
C2=[handles.C==2];
C3=[handles.C==3];
C4=[handles.C==4];
D= [M <5];
numPixels=sum(sum(D));
Max_rate = -100;
for i=1:24
    Cperm=P(i,1)*C1+P(i,2)*C2+P(i,3)*C3+P(i,4)*C4;
    rate=100*sum(sum(D.*[Cperm==M]))/numPixels;
    if rate >= Max_rate
        Max_rate = rate;
        axes(handles.axes2);
        imagesc(Cperm,[1 5]);
    end;
end
set(handles.errorbox,'String',['Classification rate =',num2str(Max_rate),'%']);
clear C1 C2 C3 C4 D Cperm M;

% --- Executes on button press in urbanBUTTON.
function urbanBUTTON_Callback(hObject, eventdata, handles)
% hObject    handle to urbanBUTTON (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
handles.choice = get(handles.ExamplePopUp,'value');
if handles.choice == 1  %Clean Urban
    clear handles.A;
    load Urban R;
    handles.A = R(:,:,[5:75,77:86,88:100,112:135,154:197]);
    clear R;
elseif handles.choice == 2  %Noisy Urban
    clear handles.A;
    load Urban R;
    handles.A = R;
    clear R;
elseif handles.choice == 3  %Terrain
    clear handles.A;
    load Terrain R;
    handles.A = R(:,:,[5:75,77:86,88:102,112:135,154:199]);
    clear R;
elseif handles.choice == 4  %Noisy Terrain
    clear handles.A;
    load Terrain R;
    handles.A = R;
    clear R;
elseif handles.choice == 5 %Indian Pines 7 band
    clear handles.A;
    load Pines R7;
    handles.A = R7;
    clear R7;
elseif handles.choice == 6 %Indian Pines 9 band
    clear handles.A;
    load Pines R9;
    handles.A = R9;
    clear R9;
elseif handles.choice == 7 %Indian Pines 220 band
    clear handles.A;
    load Pines R220;
    handles.A = R220;
    clear R220;
end;
axes(handles.axes1);
x=get(handles.bandslider1,'value');
[n1,n2,N]=size(handles.A);
set(handles.bandslider1,'SliderStep',[(1/N),0.1]);
j=round((N-1)*x+1);
imagesc(handles.A(:,:,j));  
s = get(handles.ColorMap,'string');
colormap(s{get(handles.ColorMap,'Value')});
set(handles.bandnumber,'string',['Band ',num2str(j),' of ',num2str(N)]);
guidata(hObject,handles);



% --- Executes on button press in signalBUTTON.
function signalBUTTON_Callback(hObject, eventdata, handles)
axes(handles.axes3);
load Urban;
[m,n,d] = size(handles.A);
if max(m,n) == 1
    handles.A = R;
    [m,n,d] = size(R);
end;
Q = zeros(4,d);
for i=1:4
    [I,J] = ind2sub(size(M),find(M==i));
    for j = 1:length(I)
        Q(i,:) = Q(i,:) + reshape(handles.A(I(j),J(j),:),[1,d]); 
    end;
    Q(i,:) = Q(i,:) / length(I);
end;
plot(Q');
axis tight;
legend('Road','Building','Tree','Grass','Location','SouthOutside');
drawnow;
axes(handles.axes1);
set(handles.errorbox,'string',['Click on point in Original Image']);
P(1,:)=round(ginput(1));
hold on;
scatter(P(1,1),P(1,2),'r');
drawnow;
hold off;
axes(handles.axes3);
hold on;
r(1,:) = handles.A(P(1,2),P(1,1),:);
plot(r,'m');
axis tight;
legend('Road','Building','Tree','Grass','Selected','Location','SouthOutside');
hold off;
drawnow;
clear R M Q P r;


% --- Executes on button press in saveBUTTON.
function saveBUTTON_Callback(hObject, eventdata, handles)
assignin ('base','hyperC',handles.C);
set(handles.runningtime,'String','Matrix hyperC written to workspace.');





% --- Executes on button press in checkspatial.
function checkspatial_Callback(hObject, eventdata, handles)
% hObject    handle to checkspatial (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of checkspatial



function weight_Callback(hObject, eventdata, handles)
% hObject    handle to weight (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of weight as text
%        str2double(get(hObject,'String')) returns contents of weight as a double


% --- Executes during object creation, after setting all properties.
function weight_CreateFcn(hObject, eventdata, handles)
% hObject    handle to weight (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end




function ExamplePopUp_Callback(hObject, eventdata, handles)

function ExamplePopUp_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


