📄 rotatetool.m
字号:
function varargout = rotatetool(varargin)% ROTATETOOL is an interface to the IMROTATE function. %% ROTATETOOL(HANDLE) rotates a single image contained in HANDLE.% HANDLE can be a handle to a figure, axes, or image object.%% To retrieve rotated image use the GETIMAGE function on the appropriate% figure window.%% USAGE:% [OUT] = ROTATETOOL(GRD), where GRD is a MxN of any class "above" UINT8 rotates the GRD% array and returns it in OUT. The GRD image's representation is computed with a linear% scaling on the [0 255] interval.% ( img = uint8(round( ((GRD - GRD_z_min) / (GRD_z_max - GRD_z_min))*255 )) )%% [OUT,HDR_OUT] = ROTATETOOL(GRD,HDR_IN), where HDR_IN is a header row vector with the GRD% coordinate referencing, outputs also an updated version of the header. This header has the% the form used by the GMT MEX programs, which is:% [x_min x_max y_min y_max z_min z_max registratrion x_inc y_inc]% registratrion is either 0 (for grid registration) or 1 to pixel registration.% Interested users that want to know more must consult the GMT manual.% NOTE: This is not the ML way of working with grids, but it's ALOT more efficient than the% standard use of MESHGRID which implies triplicating the memory use.%% [OUT] = ROTATETOOL(IMG), IMG is a uint8 indexed or RGB array rotates the IMG% array and returns it in OUT.%% [OUT] = ROTATETOOL(IMG,CMAP), uses the colormap CMAP in the preview image. If CMAP is% not given in input and the image is indexed, a cmap = jet(256) is used.%% [OUT,HDR_OUT] = ROTATETOOL(IMG,HDR_IN,CMAP), IMG is a uint8 indexed or RGB array. Same as% above, but with a header info vector like in the GRD case. Use this for example if the% IMG comes from a georeferenced image.%% The "Apply n return" button performs the rotation on the input data and returns% the output if it was requested.%% The "Cancel" button just closes this figure returns nothing%% EXAMPLES:% I = checkerboard(50);% h = imshow(I);% rotatetool(h) % When satisfied push 'Apply n return' then call GETIMAGE% B = getimage(gcf);%% Operate on a double array, and get it rotated% Z = peaks(128);% grd = rotatetool(Z,jet(256));%% Let us pretend that the Z obove is a referenced grid. So contruct first the HDR_IN vector% hdr_in = [1 128 1 128 min(Z(:)) max(Z(:)) 0 1 1];% [grd,hdr] = rotatetool(Z,hdr_in);%% Demonstration mode% rotatetool % displays 'peppers.png' and opens GUI.%% THIS GUI NEEDS THE IMAGE PROCESSING TOOLBOX TO RUN%% CREDITS% This GUI is a pure imitation of ROTATEGUI from Birju Patel and uses some code from% that function. However, it has extended functionalities and was re-writen using R13% syntax. Which means that it can be compiled with the V3.x compiler.%%% AUTHOR hObject = figure('Tag','figure1','Visible','off');handles = guihandles(hObject);guidata(hObject, handles);rotatetool_LayoutFcn(hObject,handles);handles = guihandles(hObject);movegui(hObject,'east')% Some initializationshandles.frame_axesPos = get(handles.frame_axes,'Pos');handles.cancel = 0; % It will be set to one if the cancel button is hit or the fig is killedhandles.angle = 0;handles.do_flipLR = false;handles.do_flipUD = false;handles.hOrigFigure = [];handles.hOrigImage = [];handles.OrigGrd = [];handles.in_hdr = []; % To hold an eventual input GMT style row vector headerhandles.out_header = []; % To hold an eventual output GMT style row vector headercmap = [];n_argout = nargout; n_argin = numel(varargin);if (n_argin >= 1) if (ishandle(varargin{1})) % First argument is an image handle, or ... error if ( strcmp(get(varargin{1},'type'),'axes') || strcmp(get(varargin{1},'type'),'fig')) handles.hOrigImage = findobj(varargin{1},'type','image'); elseif ( strcmp(get(varargin{1},'type'),'image') ) handles.hOrigImage = varargin{1}; end msg = []; if (isempty(handles.hOrigImage) || numel(handles.hOrigImage) > 1) msg = 'ERROR: None or more than one image objects found in the figure.'; end if (n_argout) msg = 'ERROR: Output arguments are not allowed when the input is a handle.'; end if (~isempty(msg)) errordlg(msg,'ERROR'); delete(hObject); return end handles.hOrigFigure = get(get(handles.hOrigImage,'Parent'),'Parent'); else if (isa(varargin{1},'uint8')) % First argument is an image array handles.OrigImage = varargin{1}; else % First arg is a "grid" handles.OrigGrd = varargin{1}; z_min = double(min(min(handles.OrigGrd))); z_max = double(max(max(handles.OrigGrd))); handles.OrigImage = uint8(round( ((double(handles.OrigGrd) - z_min) / (z_max - z_min))*255 )); cmap = jet(256); end end if (n_argin == 2 && size(varargin{2},1) == 1) % Second argument is a GMT style vector header handles.in_hdr = varargin{2}; elseif (n_argin == 2 && size(varargin{2},2) == 3) % Second argument is a colormap cmap = varargin{2}; end if (n_argin == 3) % There is no choice in args order here handles.in_hdr = varargin{2}; cmap = varargin{3}; end % One last test on CMAP & HEADER likelihood msg = []; if (~isempty(handles.in_hdr) && size(handles.in_hdr,2) < 4) msg = 'ERROR: The GMT header vector is invalid'; end if (~isempty(cmap) && size(cmap,2) ~= 3) msg = 'ERROR: Invalid colormap in imput'; end if (~isempty(msg)) errordlg(msg,'ERROR'); delete(hObject); return endelse % Demo mode h = figure; handles.hOrigImage = imshow('peppers.png'); %handles.hOrigImage = imshow('pout.tif'); handles.hOrigFigure = h;end% Determine resize needed so that preivew image fits in defined area% ReductionFactor determines how to scale original image so% that it fits in the defined preview area.pImageConstr = min(handles.frame_axesPos(3),handles.frame_axesPos(4)); %Constraining dimension in image panelif (~isempty(handles.hOrigImage)) [oriImageHeight,oriImageWidth,k] = size(get(handles.hOrigImage,'Cdata'));else [oriImageHeight,oriImageWidth,k] = size(handles.OrigImage);end%Length of Image diagonal in pixels. +5 added to allow for some panel border effectsdImage = ceil(sqrt(oriImageHeight^2 + oriImageWidth^2)) + 5;reductionFactor = (pImageConstr/dImage);if (~isempty(handles.hOrigImage)) handles.previewImage = imresize(get(handles.hOrigImage,'Cdata'),reductionFactor);else handles.previewImage = imresize(handles.OrigImage,reductionFactor);end[imHeight,imWidth,k] = size(handles.previewImage);% Center axes containing preview image in the "image panel" so rotation will look like a pin-wheel[leftPosition,bottomPosition] = calcPosition(handles,imWidth,imHeight); % Make the position relative to frame_axes LL cornerleftPosition = leftPosition + handles.frame_axesPos(1);bottomPosition = bottomPosition + handles.frame_axesPos(2);set(handles.axes1,'Pos',[leftPosition bottomPosition imWidth imHeight],... 'DataAspectRatio', [1 1 1], 'PlotBoxAspectRatioMode', 'auto')%display image in axeshandles.himage = displayPreviewImage(handles,handles.previewImage,cmap);%------------ Give a Pro look (3D) to the frame boxes -------------------------------bgcolor = get(0,'DefaultUicontrolBackgroundColor');framecolor = max(min(0.65*bgcolor,[1 1 1]),[0 0 0]);set(0,'Units','pixels'); set(hObject,'Units','pixels') % Pixels are easier to reason withh_f = findobj(hObject,'Style','Frame');for i=1:length(h_f) frame_size = get(h_f(i),'Position'); f_bgc = get(h_f(i),'BackgroundColor'); usr_d = get(h_f(i),'UserData'); if abs(f_bgc(1)-bgcolor(1)) > 0.01 % When the frame's background color is not the default's frame3D(hObject,frame_size,framecolor,f_bgc,usr_d) else frame3D(hObject,frame_size,framecolor,'',usr_d) delete(h_f(i)) endend%------------- END Pro look (3D) -------------------------------------------------------% Choose default command line output for rotatetoolhandles.output = hObject;if (n_argout == 1 && isempty(handles.OrigGrd)) % This the only case where the Fig handle can go out varargout{1} = hObject;endif (n_argout == 2) handles.out_header = 1; set(handles.popup_bboxmenu,'Enable','off') % Don't want the head-ache of computing new limitsendhandles.n_argout = n_argout;guidata(hObject, handles);set(hObject,'Visible','on');% Check if we have to do a uiwait and what goes out (if anything)if (n_argout > 0) % If called with output, we must wait uiwait(hObject); handles = guidata(hObject); if (handles.cancel) % Don't try to output eventual non-existing variables if (n_argout == 1), varargout{1} = []; end if (n_argout == 2), varargout{1} = []; varargout{2} = []; end delete(handles.figure1); % The figure can be deleted now return end varargout{1} = handles.output_grd; if (n_argout == 2) varargout{2} = handles.out_header; end delete(handles.figure1); % The figure can be deleted nowend% ----------------------------------------------------------------------------function push_cw90_Callback(hObject, eventdata, handles) % When the rotation button is pushed repeatedly, the rotation % applied to the image is cumulative. Pushing the cw button n % times will rotate preview image 90*n degrees. updateAngleInfo(handles,90); updateImage(handles);% ----------------------------------------------------------------------------function push_ccw90_Callback(hObject, eventdata, handles) updateAngleInfo(handles,-90); updateImage(handles);% ----------------------------------------------------------------------------function push_flipLR_Callback(hObject, eventdata, handles) newCdata = flipdim(get(handles.himage,'CData'),2); set(handles.himage,'Cdata',newCdata); handles.do_flipLR = ~handles.do_flipLR; % For the Apply button guidata(handles.figure1,handles)% ----------------------------------------------------------------------------function push_flipUD_Callback(hObject, eventdata, handles) newCdata = flipdim(get(handles.himage,'CData'),1); set(handles.himage,'Cdata',newCdata); handles.do_flipUD = ~handles.do_flipUD; guidata(handles.figure1,handles)% ----------------------------------------------------------------------------function slider_Callback(hObject, eventdata, handles) % Affordance for manual rotation. User can drag slider to rotate preview % image in small increments. The slider boundaries are [-180, 180]. % Text box next to slider will show values within this range. handles.angle = get(hObject,'Value'); guidata(handles.figure1,handles) updateImage(handles); set(handles.edit_angRot,'String',num2str(handles.angle));% ----------------------------------------------------------------------------function edit_angRot_Callback(hObject, eventdata, handles) % User can enter in a single scalar number (rotation angle in degrees) and image % will be rotated by that amount. If the input angle is out of the [-180,180] % range, the value will be wrapped into this range using the checkAngle function. textvalue = str2double(get(hObject,'String')); % Expression not allowe in text field. if (~isempty(textvalue) && ~isnan(textvalue) && isreal(textvalue)) handles.angle = checkAngle(textvalue); guidata(handles.figure1,handles) updateImage(handles); set(handles.slider,'Value',handles.angle); set(hObject,'String',num2str(handles.angle)); else errordlg('Text field must contain a single scalar value.') end% ----------------------------------------------------------------------------function popup_bboxmenu_Callback(hObject, eventdata, handles) % changes bounding box option for IMROTATE updateImage(handles);% ----------------------------------------------------------------------------function popup_interpmenu_Callback(hObject, eventdata, handles) % changes to interp method won't be noticeable in preview image so the preview % image will always use nearest interp. But we need to record the selected % option in case the user exits without further rotations to image val = get(hObject,'Value'); switch val case 1, handles.interpmethod = 'nearest'; case 2, handles.interpmethod = 'bilinear'; case 3, handles.interpmethod = 'bicubic'; end guidata(handles.figure1,handles)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -