Mercurial > hg > octave-image
changeset 186:13c6a9bdec24
Changed the structure to match the package system
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License.
new file mode 100644 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,10 @@ +Name: Image +Version: 1.0.0 +Date: 2006-08-05 +Author: Various Authors +Maintainer: The Octave Community +Title: Image Processing. +Description: Add a description to this package! +Depends: octave (>= 2.9.7) +License: GPL version 2 or later +Url: http://octave.sf.net
deleted file mode 100644 --- a/MakeShears.m +++ /dev/null @@ -1,7 +0,0 @@ -function [S1, S2] = MakeShears(theta) - -S1 = eye(2); -S2 = eye(2); - -S1(1,2) = -tan(theta/2); -S2(2,1) = sin(theta);
deleted file mode 100644 --- a/Makeconf.add +++ /dev/null @@ -1,3 +0,0 @@ -@DEFHAVE_JPEG@ -@DEFHAVE_PNG@ -@DEFHAVE_MAGICKXX@
deleted file mode 100644 --- a/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -sinclude ../../Makeconf - -ifdef HAVE_JPEG - JPEG=jpgwrite.oct jpgread.oct -endif - -ifdef HAVE_PNG - PNG=pngread.oct pngwrite.oct -endif - -ifdef HAVE_MAGICKXX - IMAGEMAGICK=__imagemagick__.oct __magick_read__$(OCTLINK) -endif - -all: cordflt2.oct bwlabel.oct bwfill.oct rotate_scale.oct \ - houghtf.oct graycomatrix.oct \ - $(JPEG) $(PNG) $(IMAGEMAGICK) - -jpgread.oct: jpgread.cc - $(MKOCTFILE) $< -ljpeg - -jpgwrite.oct: jpgwrite.cc - $(MKOCTFILE) $< -ljpeg - -pngread.oct: pngread.cc - $(MKOCTFILE) $< -lpng - -pngwrite.oct: pngwrite.cc - $(MKOCTFILE) $< -lpng - -__imagemagick__.oct: __imagemagick__.cc - $(MKOCTFILE) $< -lMagick++ -lMagick - -__magick_read__$(OCTLINK): __imagemagick__.oct - $(MKOCTLINK) __imagemagick__.oct $@ - -clean: ; -$(RM) *.o octave-core core *.oct *~
deleted file mode 100644 --- a/__imagemagick__.cc +++ /dev/null @@ -1,310 +0,0 @@ -#include <octave/oct.h> -#include <Magick++.h> -#include <iostream> -using namespace std; -using namespace Magick; - -octave_value_list read_indexed_images(vector<Image> imvec, Array<int> frameidx, bool wantalpha) -{ - octave_value_list output; - int rows = imvec[0].baseRows(); - int columns = imvec[0].baseColumns(); - int nframes = frameidx.length(); - ImageType type = imvec[0].type(); - - unsigned int mapsize = imvec[0].colorMapSize(); - int i = mapsize; - unsigned int depth = 0; - while(i >>= 1) depth++; - i = 0; - depth--; - while(depth >>= 1) i++; - depth = 1 << i; - - int x, y, frame; - const IndexPacket *pix; - switch(depth) { - case 1: - case 2: - case 4: - case 8: - { - uint8NDArray im = uint8NDArray(dim_vector(rows, columns, nframes)); - for(frame=0; frame < nframes; frame++) { - imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); - pix = imvec[frameidx(frame)].getConstIndexes(); - i = 0; - for(y=0; y < rows; y++) { - for(x=0; x < columns; x++) { - im(y, x, frame) = static_cast<octave_uint8>(pix[i++]); - } - } - } - im.chop_trailing_singletons(); - output(0) = octave_value(im); - } - break; - case 16: - { - uint16NDArray im = uint16NDArray(dim_vector(rows, columns, nframes)); - for(frame=0; frame < nframes; frame++) { - imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); - pix = imvec[frameidx(frame)].getConstIndexes(); - i = 0; - for(y=0; y < rows; y++) { - for(x=0; x < columns; x++) { - im(y, x, frame) = static_cast<octave_uint16>(pix[i++]); - } - } - } - im.chop_trailing_singletons(); - output(0) = octave_value(im); - } - break; - default: - error("Index depths bigger than 16-bit not supported"); - return octave_value_list(); - } - - ColorRGB c; - Matrix map = Matrix(mapsize, 3); - Matrix alpha; - switch(type) { - case PaletteMatteType: -/* warning("palettematte"); - map = Matrix(mapsize, 3); - alpha = Matrix(mapsize, 1); - for(i = 0; i < mapsize; i++) { - warning("%d", i); - c = imvec[0].colorMap(i); - map(i, 0) = c.red(); - map(i, 1) = c.green(); - map(i, 2) = c.blue(); - alpha(i, 1) = c.alpha(); - } - break; */ - case PaletteType: - alpha = Matrix(0,0); - for(i = 0; i < mapsize; i++) { - c = imvec[0].colorMap(i); - map(i, 0) = c.red(); - map(i, 1) = c.green(); - map(i, 2) = c.blue(); - } - break; - default: - error("Unsupported indexed image type"); - return octave_value_list(); - } - - output(1) = octave_value(map); - if(wantalpha) { - output(2) = octave_value(alpha); - } - return output; -} - -template <class T> -octave_value_list read_images(vector<Image> imvec, Array<int> frameidx) -{ - int i; - T im; - int rows = imvec[0].baseRows(); - int columns = imvec[0].baseColumns(); - int nframes = frameidx.length(); - ImageType type = imvec[0].type(); - - int x, y, frame; - const PixelPacket *pix; - dim_vector idim = dim_vector(); - idim.resize(4); - idim(0) = rows; - idim(1) = columns; - idim(2) = 1; - idim(3) = nframes; - Array<int> idx(dim_vector(4)); - switch(type) { - case BilevelType: - // break; - case GrayscaleType: - im = T(dim_vector(rows, columns, nframes)); - for(frame=0; frame < nframes; frame++) { - pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); - i = 0; - for(y=0; y < rows; y++) { - for(x=0; x < columns; x++) { - im(y, x, frame) = pix[i++].red; - } - } - } - break; - case GrayscaleMatteType: - idim(2) = 2; - im = T(idim); - for(frame=0; frame < nframes; frame++) { - idx(3) = frame; - i = 0; - pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); - for(y=0; y < rows; y++) { - idx(0) = y; - for(x=0; x < columns; x++) { - idx(1) = x; - idx(2) = 0; - im(idx) = pix[i].red; - idx(2) = 1; - im(idx) = pix[i].opacity; - i++; - } - } - } - break; - case PaletteType: - case TrueColorType: - idim(2) = 3; - im = T(idim); - for(frame=0; frame < nframes; frame++) { - idx(3) = frame; - i = 0; - pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); - for(y=0; y < rows; y++) { - idx(0) = y; - for(x=0; x < columns; x++) { - idx(1) = x; - idx(2) = 0; - im(idx) = pix[i].red; - idx(2) = 1; - im(idx) = pix[i].green; - idx(2) = 2; - im(idx) = pix[i].blue; - i++; - } - } - } - break; - case PaletteMatteType: - case TrueColorMatteType: - case ColorSeparationType: - idim(2) = 4; - im = T(idim); - for(frame=0; frame < nframes; frame++) { - idx(3) = frame; - i = 0; - pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); - for(y=0; y < rows; y++) { - idx(0) = y; - for(x=0; x < columns; x++) { - idx(1) = x; - idx(2) = 0; - im(idx) = pix[i].red; - idx(2) = 1; - im(idx) = pix[i].green; - idx(2) = 2; - im(idx) = pix[i].blue; - idx(2) = 3; - im(idx) = pix[i].opacity; - i++; - } - } - } - break; - default: - error("Undefined Imagemagick image type"); - return octave_value_list(); - } - - im.chop_trailing_singletons(); - return octave_value_list(octave_value(im)); -} - -// instantiate templates -template octave_value_list read_images<boolNDArray>(vector<Image>, Array<int>); -template octave_value_list read_images<uint8NDArray>(vector<Image>, Array<int>); -template octave_value_list read_images<uint16NDArray>(vector<Image>, Array<int>); - -DEFUN_DLD(__magick_read__, args, nargout, -"function m = __imagemagick_read__(fname[, index])\n\ -function [m, colormap] = __imagemagick_read__(fname[, index])\n\ -function [m, colormap, alpha] = __imagemagick_read__(fname[, index])\n\ -\n\ -Read images with ImageMagick++. User interface in imread.m.\n\ -\n\ -") -{ - octave_value_list output; - int i; - if(args.length() > 2 || args.length() < 1 || !args(0).is_string() \ - || nargout > 3) { - print_usage (); - return octave_value_list(); - } - Array<int> frameidx; - if(args.length() == 2 && args(1).is_real_type()) { - frameidx = args(1).int_vector_value(); - } else { - frameidx = Array<int>(1); - frameidx(0) = 1; - } - - vector<Image> imvec; - try { - // Read a file into vector of image objects - readImages(&imvec, args(0).string_value()); - } - catch( Warning &warning_ ) { - warning("Magick++ warning: %s", warning_.what()); - } - catch( ErrorCoder &error_) { - warning("Magick++ coder error: %s", error_.what()); - } - catch( Exception &error_ ) { - error("Magick++ exception: %s", error_.what()); - imvec.clear(); - return octave_value_list(); - } - - int nframes = imvec.size(); - for(i = 0; i < frameidx.length(); i++) { - frameidx(i) = frameidx(i) - 1; - if(frameidx(i) >= nframes || frameidx(i) < 0) { - error("Invalid index vector"); - imvec.clear(); - return output; - } - } - - ClassType klass = imvec[0].classType(); - if(klass == PseudoClass && nargout > 1) { - output = read_indexed_images(imvec, frameidx, (nargout == 3)); - } else { - int depth = imvec[0].modulusDepth(); - i = 0; - while(depth >>= 1) i++; - depth = 1 << i; - - switch(depth) { - case 1: - output = read_images<boolNDArray>(imvec, frameidx); - break; - case 2: - case 4: - case 8: - output = read_images<uint8NDArray>(imvec, frameidx); - break; - case 16: - output = read_images<uint16NDArray>(imvec, frameidx); - break; - case 32: - case 64: - default: - error("Image depths bigger than 16-bit not supported"); - } - if(nargout > 1) { - output(1) = Matrix(0,0); - if(nargout > 2) - output(2) = Matrix(0,0); - } - } - imvec.clear(); - - return output; -}
deleted file mode 100644 --- a/applylut.m +++ /dev/null @@ -1,62 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{A} = } applylut (@var{BW},@var{LUT}) -## Uses lookup tables to perform a neighbour operation on binary images. -## -## A = applylut(BW,LUT) returns the result of a neighbour operation -## using the lookup table @var{LUT} which can be created by makelut. -## -## It first computes a matrix with the index of each element in the -## lookup table. To do this, it convolves the original matrix with a -## matrix which assigns each of the neighbours a bit in the resulting -## index. Then @var{LUT} is accessed to compute the result. -## -## @end deftypefn -## @seealso{makelut} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function A = applylut(BW, LUT) - if (nargin != 2) - usage ("A = applylut(BW, LUT)"); - endif - - nq=log2(length(LUT)); - n=sqrt(nq); - if (floor(n)!=n) - error ("applylut: LUT length is not as expected. Use makelut to create it."); - endif - w=reshape(2.^[nq-1:-1:0],n,n); - A=LUT(filter2(w,BW)+1); -endfunction - -%!demo -%! lut=makelut(inline('sum(x(:))>=3','x'), 3); -%! applylut(eye(5),lut) -%! % everything should be 0 despite a diagonal which -%! % doesn't reach borders. - - -%!assert(prod(applylut(eye(3),makelut(inline('x(1,1)==1','x'),2))==eye(3))==1); % 2-by-2 test -%!assert(prod(applylut(eye(3),makelut(inline('x(2,2)==1','x'),3))==eye(3))==1); % 3-by-3 test -%!assert(prod(applylut(eye(3),makelut(inline('x(3,3)==1','x'),3))== \ -%! applylut(eye(3),makelut(inline('x(2,2)==1','x'),2)))==1); - - - -
deleted file mode 100644 --- a/autumn.m +++ /dev/null @@ -1,51 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} autumn (@var{n}) -## Create color colormap. -## (red through orange to yellow) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = autumn (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("autumn: argument must be a scalar"); - endif - else - usage ("autumn (number)"); - endif - - if (number == 1) - map = [1, 0, 0]; - elseif (number > 1) - r = ones (number, 1); - g = (0:number - 1)' ./ (number - 1); - b = zeros (number, 1); - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/bestblk.m +++ /dev/null @@ -1,110 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{siz} = } bestblk ([@var{m} @var{n}], @var{k}) -## @deftypefnx {Function File} {[@var{mb} @var{nb}] = } bestblk ([@var{m} @var{n}], @var{k}) -## Calculates the best size of block for block processing. -## -## @code{siz=bestblk([m,n],k)} calculates the optimal block size for block -## processing for a @var{m}-by-@var{n} image. @var{k} is the maximum -## side dimension of the block. Its default value is 100. @var{siz} is a -## row vector which contains row and column dimensions for the block. -## -## @code{[mb,nb]=bestblk([m,n],k)} behaves as described above but -## returns block dimensions to @var{mb} and @var{nb}. -## -## @strong{Algorithm:} -## -## For each dimension (@var{m} and @var{n}), it follows this algorithm: -## -## 1.- If dimension is less or equal than @var{k}, it returns the -## dimension value. -## -## 2.- If not then returns the value between -## @code{round(min(dimension/10,k/2))} which minimizes padding. -## -## -## @end deftypefn -## @seealso{blkproc} - - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function [varargout] = bestblk(ims,k) - if(nargin<1 || nargin>2) - usage("siz=bestblk([m,n],k), [mb,nb]=bestblk([m,n],k)"); - endif - if(nargout>2) - usage("siz=bestblk([m,n],k), [mb,nb]=bestblk([m,n],k)"); - endif - if(nargin<2) - k=100; - endif - if(!isvector(ims)) - error("bestblk: first parameter is not a vector."); - endif - ims=ims(:); - if(length(ims)!=2) - error("bestblk: length of first parameter is not 2."); - endif - - mb=mi=ims(1); - p=mi; - if(mi>k) - for i=round(min(mi/10,k/2)):k - pt=rem(mi,i); - if(pt<p) - p=pt; - mb=i; - endif - endfor - endif - - nb=ni=ims(2); - p=ni; - if(ni>k) - for i=round(min(ni/10,k/2)):k - pt=rem(ni,i); - if(pt<p) - p=pt; - nb=i; - endif - endfor - endif - - if(nargout<=1) - varargout{1}=[mb;nb]; - else - varargout{1}=mb; - varargout{2}=nb; - endif - -endfunction - -%!demo -%! siz=bestblk([200;10],50) -%! # Best block is [20,10] - -%!assert(bestblk([300;100],150),[30;100]); -%!assert(bestblk([256,128],17),[16;16]); - -% $Log$ -% Revision 1.2 2005/07/03 01:10:19 pkienzle -% Try to correct for missing newline at the end of the file -% -% Revision 1.1 2004/08/15 19:01:05 jmones -% bestblk added: Calculates best block size for block processing
deleted file mode 100644 --- a/blkproc.m +++ /dev/null @@ -1,190 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{B} = } blkproc (@var{A}, [@var{m},@var{n}], @var{fun}) -## @deftypefnx {Function File} {@var{B} = } blkproc (@var{A}, [@var{m},@var{n}], @var{fun}, ...) -## @deftypefnx {Function File} {@var{B} = } blkproc (@var{A}, [@var{m},@var{n}], [@var{mborder},@var{nborder}], @var{fun}, @var{...}) -## @deftypefnx {Function File} {@var{B} = } blkproc (@var{A}, 'indexed', ...) -## Processes image in blocks using user-supplied function -## -## @code{B=blkproc(A,[m,n],fun)} divides image @var{A} in -## @var{m}-by-@var{n} blocks, and passes them to user-supplied function -## @var{fun}, which result is concatenated to build returning matrix -## @var{B}. If padding is needed to build @var{m}-by-@var{n}, it is added -## at the bottom and right borders of the image. 0 is used as a padding -## value. -## -## @code{B=blkproc(A,[m,n],fun,...)} behaves as described above but -## passes extra parameters to function @var{fun}. -## -## @code{B=blkproc(A,[m,n],[mborder,nborder],fun,...)} behaves as -## described but uses blocks which overlap with neighbour blocks. -## Overlapping dimensions are @var{mborder} vertically and @var{nborder} -## horizontally. This doesn't change the number of blocks in an image -## (which depends only on size(@var{A}) and [@var{m},@var{n}]). Adding a -## border requires extra padding on all edges of the image. 0 is used as -## a padding value. -## -## @code{B=blkproc(A,'indexed',...)} assumes that @var{A} is an indexed -## image, so it pads the image using proper value: 0 for uint8 and -## uint16 images and 1 for double images. Keep in mind that if 'indexed' -## is not specified padding is always done using 0. -## -## @end deftypefn -## @seealso{colfilt,inline,bestblk} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function B = blkproc(A, varargin) - if(nargin<3) - error("blkproc: invalid number of parameters."); - endif - - ## check 'indexed' presence - indexed=false; - p=1; - if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) - indexed=true; - p+=1; - if(isa(A,"uint8") || isa(A,"uint16")) - padval=0; - else - padval=1; - endif - else - padval=0; - endif - - ## check [m,n] - if(!isvector(varargin{p})) - error("blkproc: expected [m,n] but param is not a vector."); - endif - if(length(varargin{p})!=2) - error("blkproc: expected [m,n] but param has wrong length."); - endif - sblk=varargin{p}(:); - p+=1; - - ## check [mborder,nborder] - if(nargin<p) - error("blkproc: required parameters haven't been supplied."); - endif - - if(isvector(varargin{p})) - if(length(varargin{p})!=2) - error("blkproc: expected [mborder,nborder] but param has wrong length."); - endif - sborder=varargin{p}(:); - p+=1; - else - sborder=[0;0]; - endif - - ## check fun - ## TODO: add proper checks for this one - if(nargin<p) - error("blkproc: required parameters haven't been supplied."); - endif - - fun=varargin{p}; - if(!isa(fun,"function handle") && - !isa(fun,"inline function") && - !ischar(fun)) - error("blkproc: invalid fun parameter."); - endif - - ## remaining params are params to fun - ## extra params are p+1:nargin-1 - - ## First of all we calc needed padding which will be applied on bottom - ## and right borders - ## The "-" makes the function output needed elements to fill another - ## block directly - sp=mod(-size(A)',sblk); - - if(any(sp)) - A=padarray(A,sp,padval,'post'); - endif - - ## we store A size without border padding to iterate later - soa=size(A); - - ## If we have borders then we need more padding - if(any(sborder)) - A=padarray(A,sborder,padval); - endif - - ## calculate end of block - eblk=sblk+sborder*2-1; - - ## now we can process by blocks - ## we try to preserve fun return type by concatenating everything - for i=1:sblk(1):soa(1) - ## This assures r has the same class as returned by fun - r=feval(fun,A(i:i+eblk(1),1:1+eblk(2)),varargin{p+1:nargin-1}); - for j=1+sblk(2):sblk(2):soa(2) - r=horzcat(r,feval(fun,A(i:i+eblk(1),j:j+eblk(2)),varargin{p+1:nargin-1})); - endfor - if(i==1) ## this assures B has the same class as A - B=r; - else - B=vertcat(B,r); - endif - endfor -endfunction - -%!demo -%! blkproc(eye(6),[2,2],inline("any(x(:))","x")) -%! # Returns a 3-by-3 diagonal - - -%!assert(blkproc(eye(6),[2,2],"sum"),blkproc(eye(6),[2,2],@sum)); -%!assert(blkproc(eye(6),[2,2],"sum"),blkproc(eye(6),[2,2],inline("sum(x)","x"))); -%!assert(blkproc(eye(6),[1,2],@sum),kron(eye(3),[1;1])); -%!assert(blkproc(eye(6),[2,2],inline("any(x(:))","x")),eye(3)!=0); -%!assert(blkproc(eye(6),[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); -%!assert(blkproc(eye(6),'indexed',[1,2],[1,1],inline("sum(x(:))","x")),[8,5,6;6,2,3;5,3,4;4,3,5;3,2,6;6,5,8]); -%!assert(blkproc(eye(6),[2,3],[4,3],inline("sum(x(:))","x")),ones(3,2)*6); - -% Some int* and uint* tests -%!assert(blkproc(eye(6),[2,2],inline("int8(sum(x(:)))","x")),eye(3,"int8")*2); - -% Padding is 0 even for indexed -%!assert(blkproc(uint8(eye(6)),[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); -%!assert(blkproc(uint8(eye(6)),'indexed',[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); -%!assert(blkproc(uint16(eye(6)),[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); -%!assert(blkproc(uint16(eye(6)),'indexed',[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); - - -% -% $Log$ -% Revision 1.5 2005/09/08 02:00:17 pkienzle -% [for Bill Denney] isstr -> ischar -% -% Revision 1.4 2004/11/15 16:04:20 pkienzle -% Fix tests for functions which return boolean matrices -% -% Revision 1.3 2004/09/03 17:49:37 jmones -% Improved uint8 and uint16 padding expections -% -% Revision 1.2 2004/09/03 13:40:13 jmones -% Check result has same class as function result, and improved fun param checking -% -% Revision 1.1 2004/08/15 19:27:46 jmones -% blkproc: block process an image using user-supplied function -% -%
deleted file mode 100644 --- a/bmpwrite.m +++ /dev/null @@ -1,88 +0,0 @@ -## bmpwrite(X,map,file) -## Write the bitmap X into file (8-bit indexed uncompressed). -## The values in X are indices into the given RGB colour map. -## bmpwrite(X,file) -## Write the bitmap X into file (24-bit truecolor uncompressed). -## X is an m x n x 3 array of R,G,B values. - -## This code is in the public domain. -## Author: Paul Kienzle <pkienzle@users.sf.net> - -function bmpwrite(x,map,file) - if nargin==2 - bmpwrite_truecolor(x,map); - else - bmpwrite_indexed(x,map,file); - endif -endfunction - -function bmpwrite_truecolor(x,file) - h = rows(x); w = columns(x); - padw = ceil(3*w/4)*4-3*w; - header = 14+40; - filesize = header+h*(3*w+padw); - arch = "ieee-le"; - file = fopen(file, "wb"); - fwrite(file,toascii("BM"),"uchar",0,arch); # file tag - fwrite(file,filesize,"long",0,arch); # length of file - fwrite(file,0,"long",0,arch); # reserved - fwrite(file,header,"long",0,arch); # offset of raster data in file - - fwrite(file,40,"long",0,arch); # header size - fwrite(file,w,"long",0,arch); # image width - fwrite(file,h,"long",0,arch); # image height - fwrite(file,1,"short",0,arch); # number of planes - fwrite(file,24,"short",0,arch); # pixels per plane - fwrite(file,0,"long",0,arch); # compression (none) - fwrite(file,0,"long",0,arch); # compressed size of image - resolution = 72/2.54*100; # 72 dpi / 2.54 cm/in * 100 cm/m - fwrite(file,resolution,"long",0,arch); # horizontal resolution - fwrite(file,resolution,"long",0,arch); # vertical resolution - fwrite(file,0,"long",0,arch); # number of colours used - fwrite(file,0,"long",0,arch); # number of "important" colors - - ## raster image, lines written bottom to top. - R = x(end:-1:1,:,1)'; - G = x(end:-1:1,:,2)'; - B = x(end:-1:1,:,3)'; - RGB=[B(:),G(:),R(:)]'; # Now [[B;G;R],[B;G;R],...,[B;G;R]] - RGB=reshape(RGB,3*w,h); # Now [[B;G;R;...;B;G;R],...,[B;G;R;...;B;G;R]] - fwrite(file,[RGB;zeros(padw,h)],"uchar",0,arch); - fclose(file); -endfunction - -function bmpwrite_indexed(x,map,file) - [h,w] = size(x); - padw = ceil(w/4)*4-w; - header = 14+40+4*rows(map); - filesize = header+(w+padw)*h; - arch = "ieee-le"; - file = fopen(file, "wb"); - fwrite(file,toascii("BM"),"uchar",0,arch); # file tag - fwrite(file,filesize,"long",0,arch); # length of file - fwrite(file,0,"long",0,arch); # reserved - fwrite(file,header,"long",0,arch); # offset of raster data in file - - fwrite(file,40,"long",0,arch); # header size - fwrite(file,w,"long",0,arch); # image width - fwrite(file,h,"long",0,arch); # image height - fwrite(file,1,"short",0,arch); # number of planes - fwrite(file,8,"short",0,arch); # pixels per plane - fwrite(file,0,"long",0,arch); # compression (none) - fwrite(file,0,"long",0,arch); # compressed size of image - resolution = 72/2.54*100; # 72 dpi / 2.54 cm/in * 100 cm/m - fwrite(file,resolution,"long",0,arch); # horizontal resolution - fwrite(file,resolution,"long",0,arch); # vertical resolution - fwrite(file,rows(map),"long",0,arch); # number of colours used - fwrite(file,0,"long",0,arch); # number of "important" colors - - ## colormap BGR0BGR0BGR0BGR0... - map=[round(map*255), zeros(rows(map),1)]; - map=map(:,[3,2,1,4]); - fwrite(file,map',"uchar",0,arch); - - ## raster image, each line on a 32-bit boundary, padded with zeros - ## lines written bottom to top. - fwrite(file,[flipud(x-1)';zeros(padw,h)],"uchar",0,arch); - fclose(file); -endfunction
deleted file mode 100644 --- a/bone.m +++ /dev/null @@ -1,54 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} bone (@var{n}) -## Create color colormap. -## (a gray colormap with a light blue tone) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = bone (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("bone: argument must be a scalar"); - endif - else - usage ("bone (number)"); - endif - - if (number == 1) - map = [0, 0, 0]; - elseif (number > 1) - x = linspace (0, 1, number)'; - - r = (x < 3/4) .* (7/8 * x) + (x >= 3/4) .* (11/8 * x - 3/8); - g = (x < 3/8) .* (7/8 * x)\ - + (x >= 3/8 & x < 3/4) .* (29/24 * x - 1/8)\ - + (x >= 3/4) .* (7/8 * x + 1/8); - b = (x < 3/8) .* (29/24 * x) + (x >= 3/8) .* (7/8 * x + 1/8); - map=[r, g, b]; - else - map = []; - endif -endfunction
deleted file mode 100644 --- a/brighten.m +++ /dev/null @@ -1,65 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{map_out}= brighten (@var{map},@var{beta}) -## @deftypefnx {Function File} @var{map_out}= brighten (@var{beta}) -## darkens or brightens the given colormap. -## If the @var{map} argument is omitted, the function is applied to the -## current colormap. -## Should the resulting colormap @var{map_out} not be assigned, it will be -## written to the current colormap. -## The argument @var{beta} should be a scalar between -1 and 1, -## where a negative value darkens and a positive value brightens -## the colormap. -## -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 05. March 2000 - -function [Rmap] = brighten (m, beta) - - if (nargin == 1) - beta = m; - m = colormap; - - elseif (nargin == 2) - if ( (!is_matrix (m)) || (size (m, 2) != 3) ) - error ("brighten(map,beta) map must be a matrix of size nx3."); - endif - - else - usage ("brighten(...) number of arguments must be 1 or 2."); - endif - - if ( (!is_scalar (beta)) || (beta <= -1) || (beta >= 1) ) - error ("brighten(...,beta) beta must be a scalar in the range (-1,1)."); - endif - - if (beta > 0) - gamma = 1 - beta; - else - gamma = 1 / (1 + beta); - endif - - if (nargout == 0) - colormap (m .^ gamma); - else - Rmap = m .^ gamma; - endif - -endfunction
deleted file mode 100644 --- a/bwarea.m +++ /dev/null @@ -1,57 +0,0 @@ -## Copyright (C) 2005 Søren Hauberg -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{total}= bwarea(@var{bw}) -## Estimates the area of the "on" pixels of @var{bw}. -## If @var{bw} is a binary image "on" pixels are defined as pixels -## valued 1. If @var{bw} is a grayscale image "on" pixels is defined -## as pixels with values larger than zero. -## This algorithm is not the same as counting the number of "on" -## pixels as it tries to estimate the area of the original object -## and not the image object. -## @end deftypefn - -## Author: Søren Hauberg <hauberg at gmail dot com> -## -## 2005-06-05 Søren Hauberg <hauberg at gmail dot com> -## * Initial revision - - -function total = bwarea(bw) - if (isgray(bw)) - bw = (bw > 0); - endif - - if (!isbw(bw)) - error("input image muste be either binary or gray scale.\n"); - endif - - four = ones(2); - two = diag([1 1]); - - fours = conv2(bw, four); - twos = conv2(bw, two); - - nQ1 = sum(fours(:) == 1); - nQ3 = sum(fours(:) == 3); - nQ4 = sum(fours(:) == 4); - nQD = sum(fours(:) == 2 & twos(:) != 1); - nQ2 = sum(fours(:) == 2 & twos(:) == 1); - - total = 0.25*nQ1 + 0.5*nQ2 + 0.875*nQ3 + nQ4 + 0.75*nQD; - -endfunction
deleted file mode 100644 --- a/bwborder.m +++ /dev/null @@ -1,35 +0,0 @@ -## Copyright (C) 2000 Etienne Grossmann -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## b = bwborder(im) -## -## b is the borders in the 0-1 matrix im. 4-neighborhood is considered. -## -## A pixel is on the border if it is set in im, and it has at least one -## neighbor that is not set. - -## Author: Etienne Grossmann <etienne@cs.uky.edu> -## Last modified: January 2000 - -function b = bwborder(im) - -[R,C]=size(im); - -b = im & ... - !([im(2:R,:) ; zeros(1,C) ] & ... - [zeros(1,C); im(1:R-1,:) ] & ... - [im(:,2:C) , zeros(R,1) ] & ... - [zeros(R,1), im(:,1:C-1)] ) ;
deleted file mode 100644 --- a/bweuler.m +++ /dev/null @@ -1,99 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{eul} = } bweuler (@var{BW},@var{n}) -## Calculates the Euler number of a binary image -## -## eul=bweuler(BW,n) calculates the Euler number @var{eul} of a binary -## image @var{BW}, which is a scalar whose value is the total number of -## objects in an image minus the number of holes. -## -## @var{n} can have the values: -## @table @code -## @item 4 -## bweuler will use 4-connected neighbourhood definition. -## @item 8 -## bweuler will use 8-connected neighbourhood definition. This is the -## default value. -## @end table -## -## This function uses Bit Quads as described in "Digital Image -## Processing" to calculate euler number. -## -## References: -## W. K. Pratt, "Digital Image Processing", 3rd Edition, pp 593-595 -## -## @end deftypefn -## @seealso qtgetblk - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function eul = bweuler(BW, n) - if(nargin<1 || nargin>2) - usage("eul=bweuler(BW,n)"); - endif - if(nargin<2) - n=8; - endif - - ## q1lut=makelut(inline("sum(x(:))==1","x"),2); - ## q3lut=makelut(inline("sum(x(:))==3","x"),2); - ## qdlut=makelut(inline("all((x==eye(2))(:))||all((x==fliplr(eye(2)))(:))","x"),2); - ## lut_4=(q1lut-q3lut+2*qdlut)/4; # everything in one lut will be quicker - ## lut_8=(q1lut-q3lut-2*qdlut)/4; - ## we precalculate this... - if(n==8) - lut=[0;.25;.25;0;.25;0;-.5;-.25;.25;-.5;0;-.25;0;-.25;-.25;0]; - elseif(n==4) - lut=[0;.25;.25;0;.25;0;.5;-.25;.25;.5;0;-.25;0;-.25;-.25;0]; - else - error("bweuler: n can only be 4 or 8."); - endif - - eul=sum(applylut(BW,lut)(:)); -endfunction - -%!demo -%! A=zeros(9,10); -%! A([2,5,8],2:9)=1; -%! A(2:8,[2,9])=1 -%! bweuler(A) -%! # Euler number (objects minus holes) is 1-2=-1 in an 8-like object - -%!test -%! A=zeros(10,10); -%! A(2:9,3:8)=1; -%! A(4,4)=0; -%! A(8,8)=0; # not a hole -%! A(6,6)=0; -%! assert(bweuler(A),-1); - -%!# This will test if n=4 and n=8 behave differently -%!test -%! A=zeros(10,10); -%! A(2:4,2:4)=1; -%! A(5:8,5:8)=1; -%! assert(bweuler(A,4),2); -%! assert(bweuler(A,8),1); -%! assert(bweuler(A),1); - -% $Log$ -% Revision 1.2 2005/07/03 01:10:19 pkienzle -% Try to correct for missing newline at the end of the file -% -% Revision 1.1 2004/08/15 19:33:20 jmones -% bweuler: Calculates the Euler number of a binary image
deleted file mode 100644 --- a/bwfill.cc +++ /dev/null @@ -1,238 +0,0 @@ -/* - * BWFILL: fill a bw image starting at points - * imo= block(im, xregs, yregs); - * - * Copyright (C) 1999 Andy Adler - * This code has no warrany whatsoever. - * Do what you like with this code as long as you - * leave this copyright in place. - * - * $Id$ - */ - -#include <octave/oct.h> - -#ifndef OCTAVE_LOCAL_BUFFER -#include <vector> -#define OCTAVE_LOCAL_BUFFER(T, buf, size) \ - std::vector<T> buf ## _vector (size); \ - T *buf = &(buf ## _vector[0]) -#endif - -#define ptUP (-1) -#define ptDN (+1) -#define ptRT (+ioM) -#define ptLF (-ioM) - -/* - * check if the point needs to be filled, if so - * fill it and change the appropriate variables - */ -void checkpoint( int pt, - unsigned char* imo, - int * ptstack, - int * npoints ) { -// printf("filling %d np=%d fill=%d\n",pt,*npoints, *(imo+pt)==0 ); - if( *(imo+pt) != 0 ) return; - - *(imo+pt) = 2; - *(ptstack + (*npoints))= pt; - (*npoints)++; -} - -DEFUN_DLD (bwfill, args, , - "[...] = bwfill (...)\n\ - [BW2,IDX] = BWFILL(BW1,Y,X,N) performs a flood-fill on BW1\n\ -\n\ - (X(k), Y(k)) are rows and columns of seed points\n\ -\n\ - [BW2,IDX] = BWFILL(BW1,'holes',N) fills interior holes in BW1\n\ -\n\ - N = 4 or 8(default) for neighborhood connectedness\n\ -\n\ - IDX is the indices of the filled pixels") -{ - octave_value_list retval; - octave_value tmp; - ColumnVector xseed, yseed ; - int nargin = args.length (); - - if (nargin < 2 ) { - print_usage (); - return retval; - } - - Matrix im= args(0).matrix_value(); - int imM= im.rows(); - int imN= im.columns(); - - int nb= 8; - int npoints= 0; - bool fillmode= false; - if (args(1).is_string() && args(1).string_value() == "holes" ) { - fillmode= true; - - npoints= 2*( imM + imN - 4 ); // don't start fill from corners - - xseed= ColumnVector( npoints ); - yseed= ColumnVector( npoints ); - int idx= 0; - for (int j=2; j<= imN-1; j++) { - xseed( idx )= j; yseed( idx++)= 1; - xseed( idx )= j; yseed( idx++)= imM; - } - - for (int i=2; i<= imM-1; i++) { - yseed( idx )= i; xseed( idx++)= 1; - yseed( idx )= i; xseed( idx++)= imN; - } - - if (nargin >= 4 ) - nb= (int) args(2).double_value(); - } // holes mode? - else { - { - ColumnVector tmp( args(2).vector_value() ); - xseed= tmp; - } - { - ColumnVector tmp( args(1).vector_value() ); - yseed= tmp; - } - npoints= xseed.length(); - if (nargin >= 4 ) - nb= (int) args(3).double_value(); - } // holes mode? - -/* - * put a one pixel thick boundary around the image - * so that we can be more efficient in the main loop - */ - int ioM= imM+2; - OCTAVE_LOCAL_BUFFER(unsigned char, imo, (imM+2) * (imN+2)); - - for (int i=0; i<imM; i++) - for (int j=0; j<imN; j++) - imo[(i+1) + ioM*(j+1)]= ( im(i,j) > 0 ) ; - - for (int i=0; i<ioM; i++) - imo[i]= imo[i + ioM*(imN+1)] = 3; - - for (int j=1; j<imN+1; j++) - imo[ioM*j]= imo[imM+1 + ioM*j] = 3; - -// This is obviously big enough for the point stack, but I'm -// sure it can be smaller. - OCTAVE_LOCAL_BUFFER(int, ptstack, ioM*imN ); - - int seedidx= npoints; - npoints= 0; - while ( (--seedidx) >= 0 ) { -// no need to add 1 to convert indexing style because we're adding a boundary - int pt= (int) xseed( seedidx )*ioM + (int) yseed( seedidx ); - checkpoint( pt , imo, ptstack, &npoints ); - } - - while ( npoints > 0 ) { - npoints--; - int pt= ptstack[ npoints ]; - - checkpoint( pt + ptLF, imo, ptstack, &npoints ); - checkpoint( pt + ptRT, imo, ptstack, &npoints ); - checkpoint( pt + ptUP, imo, ptstack, &npoints ); - checkpoint( pt + ptDN, imo, ptstack, &npoints ); - - if (nb==8) { - checkpoint( pt + ptLF + ptUP, imo, ptstack, &npoints ); - checkpoint( pt + ptRT + ptUP, imo, ptstack, &npoints ); - checkpoint( pt + ptLF + ptDN, imo, ptstack, &npoints ); - checkpoint( pt + ptRT + ptDN, imo, ptstack, &npoints ); - } - } // while ( npoints - - Matrix imout( imM, imN ); - ColumnVector idxout (imM*imN ); - int idx=0; - - int notvalidpt= 0; - int idxpoint= 2; - if ( fillmode ) { - notvalidpt= 2; - idxpoint= 0; - } - - for (int i=0; i<imM; i++) - for (int j=0; j<imN; j++) { - imout(i,j) = (double) ( imo[(i+1) + ioM*(j+1)] != notvalidpt ); - if ( imo[(i+1) + ioM*(j+1)] == idxpoint ) - idxout(idx++) = (double) (i + j*imM + 1); - } - - /* - Matrix imout( imM+2, imN+2 ); - for (int i=0; i<imM+2; i++) - for (int j=0; j<imN+2; j++) - imout(i,j) = (double) imo[i + ioM*j]; - */ - - retval(0)= imout; -// we need to do this to be able to return a proper empty vector - if (idx > 0) - retval(1)= idxout.extract(0, idx-1); - else - retval(1)= ColumnVector ( 0 ); - return retval; -} - - -/* - * $Log$ - * Revision 1.7 2006/05/19 06:58:50 jwe - * *** empty log message *** - * - * Revision 1.5 2003/05/15 21:25:40 pkienzle - * OCTAVE_LOCAL_BUFFER now requires #include <memory> - * - * Revision 1.4 2003/03/05 15:31:52 pkienzle - * Backport to octave-2.1.36 - * - * Revision 1.3 2003/02/20 23:03:57 pkienzle - * Use of "T x[n]" where n is not constant is a g++ extension so replace it with - * OCTAVE_LOCAL_BUFFER(T,x,n), and other things to keep the picky MipsPRO CC - * compiler happy. - * - * Revision 1.2 2002/11/02 10:39:36 pkienzle - * gcc 3.2 wants \n\ for multi-line strings. - * - * Revision 1.1 2002/03/17 02:38:51 aadler - * fill and edge detection operators - * - * Revision 1.9 2000/06/16 20:22:47 aadler - * mods for 2.1/2.0 compat - * - * Revision 1.8 2000/06/13 17:27:24 aadler - * mods for 2.1.30 - * - * Revision 1.7 1999/06/10 19:42:12 aadler - * minor verbose fix - * - * Revision 1.6 1999/06/08 16:30:30 aadler - * bug fix. reversed r,c input arguments - * - * Revision 1.5 1999/06/08 15:41:02 aadler - * now fills in holes - * - * Revision 1.4 1999/06/08 15:21:02 aadler - * fixed bug that so specified points are only used if they can fill - * - * Revision 1.3 1999/06/08 15:05:08 aadler - * now returns 1 and gives index output - * - * Revision 1.2 1999/06/04 21:58:57 aadler - * fixed 8 vs 4 neighborhood - * - * Revision 1.1 1999/06/04 21:43:20 aadler - * Initial revision - * - * - */
deleted file mode 100644 --- a/bwlabel.cc +++ /dev/null @@ -1,238 +0,0 @@ -/* --------------------------------------------------------------------- - - bwimage.cc - octave module to label componenets of a binary image - - copyright 2002 Jeffrey E. Boyd - - - uses 4, 6, or 8 connectedness - - See BKP Horn, Robot Vision, MIT Press, 1986, p 66 - 71 - - labeling scheme - - +-+-+-+ - |D|C|E| - +-+-+-+ - |B|A| | - +-+-+-+ - | | | | - +-+-+-+ - - A is the center pixel of a neighborhood. In the 3 versions of - connectedness: - - 4: A connects to B and C - 6: A connects to B, C, and D - 8: A connects to B, C, D, and E - - ---------------------------------------------------------------------- */ - - - -#include <oct.h> -#ifndef OCTAVE_LOCAL_BUFFER -#include <vector> -#define OCTAVE_LOCAL_BUFFER(T, buf, size) \ - std::vector<T> buf ## _vector (size); \ - T *buf = &(buf ## _vector[0]) -#endif - - - -#define NO_OBJECT 0 -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) - - - -static int find( int *, int ); - -static bool any_bad_argument( const octave_value_list& ); - - -/* -%!assert(bwlabel([0 1 0; 0 0 0; 1 0 1]),[0 1 0; 0 0 0; 2 0 3]); -*/ -DEFUN_DLD(bwlabel, args, , -"\n\ -[l,num] = bwlabel( bw, n ) - label foreground components of boolean image\n\ -\n\ - bw - boolean image array\n\ - n - neighborhood connectedness (4, 6,or 8)\n\ -\n\ - l - label image array\n\ - num - number of components labeled\n\ -\n\ - The algorithm is derived from BKP Horn, Robot Vision, MIT Press,\n\ - 1986, p 65 - 89 \n" ) -{ - if ( any_bad_argument(args) ) - return octave_value_list(); - - // input arguments - Matrix BW = args(0).matrix_value(); // the input binary image - int n; - if ( args.length() < 2 ) n = 6; // n-hood connectivity - else n = args(1).int_value(); - int nr = args(0).rows(); - int nc = args(0).columns(); - - // results - Matrix L( nr, nc ); // the label image - int nobj; // number of objects found in image - - // other variables - int ntable; // number of elements in the component table/tree - - OCTAVE_LOCAL_BUFFER(int, lset, nr * nc); // label table/tree - ntable = 0; - lset[0] = 0; - - for( int r = 0; r < nr; r++ ) { - for( int c = 0; c < nc; c++ ) { - if ( BW.elem(r,c) ) { // if A is an object - // get the neighboring pixels B, C, D, and E - int B, C, D, E; - if ( c == 0 ) B = 0; else B = find( lset, (int)L.elem(r,c-1) ); - if ( r == 0 ) C = 0; else C = find( lset, (int)L.elem(r-1,c) ); - if ( r == 0 || c == 0 ) D = 0; else D = find( lset, (int)L.elem(r-1,c-1) ); - if ( r == 0 || c == nc - 1 ) E = 0; - else E = find( lset, (int)L.elem(r-1,c+1) ); - - if ( n == 4 ) { - // apply 4 connectedness - if ( B && C ) { // B and C are labeled - if ( B == C ) - L.elem(r,c) = B; - else { - lset[C] = B; - L.elem(r,c) = B; - } - } else if ( B ) // B is object but C is not - L.elem(r,c) = B; - else if ( C ) // C is object but B is not - L.elem(r,c) = C; - else { // B, C, D not object - new object - // label and put into table - ntable++; - L.elem(r,c) = lset[ ntable ] = ntable; - } - } else if ( n == 6 ) { - // apply 6 connected ness - if ( D ) // D object, copy label and move on - L.elem(r,c) = D; - else if ( B && C ) { // B and C are labeled - if ( B == C ) - L.elem(r,c) = B; - else { - int tlabel = MIN(B,C); - lset[B] = tlabel; - lset[C] = tlabel; - L.elem(r,c) = tlabel; - } - } else if ( B ) // B is object but C is not - L.elem(r,c) = B; - else if ( C ) // C is object but B is not - L.elem(r,c) = C; - else { // B, C, D not object - new object - // label and put into table - ntable++; - L.elem(r,c) = lset[ ntable ] = ntable; - } - } else if ( n == 8 ) { - // apply 8 connectedness - if ( B || C || D || E ) { - int tlabel = B; - if ( B ) tlabel = B; - else if ( C ) tlabel = C; - else if ( D ) tlabel = D; - else if ( E ) tlabel = E; - L.elem(r,c) = tlabel; - if ( B && B != tlabel ) lset[B] = tlabel; - if ( C && C != tlabel ) lset[C] = tlabel; - if ( D && D != tlabel ) lset[D] = tlabel; - if ( E && E != tlabel ) lset[E] = tlabel; - } else { - // label and put into table - ntable++; - L.elem(r,c) = lset[ ntable ] = ntable; - } - } - } else { - L.elem(r,c) = NO_OBJECT; // A is not an object so leave it - } - } - } - - // consolidate component table - for( int i = 0; i <= ntable; i++ ) - lset[i] = find( lset, i ); - - // run image through the look-up table - for( int r = 0; r < nr; r++ ) - for( int c = 0; c < nc; c++ ) - L.elem(r,c) = lset[ (int)L.elem(r,c) ]; - - // count up the objects in the image - for( int i = 0; i <= ntable; i++ ) - lset[i] = 0; - - for( int r = 0; r < nr; r++ ) - for( int c = 0; c < nc; c++ ) - lset[ (int)L.elem(r,c) ]++; - - // number the objects from 1 through n objects - nobj = 0; - lset[0] = 0; - for( int i = 1; i <= ntable; i++ ) - if ( lset[i] > 0 ) - lset[i] = ++nobj; - - // run through the look-up table again - for( int r = 0; r < nr; r++ ) - for( int c = 0; c < nc; c++ ) - L.elem(r,c) = lset[ (int)L.elem(r,c) ]; - - octave_value_list rval; - rval(0) = L; - rval(1) = (double)nobj; - return rval; -} - - -static bool any_bad_argument( const octave_value_list& args ) -{ - if ( args.length() < 1 || args.length() > 2 ) { - error( "bwlabel: number of arguments - expecting bwlabel(bw) or bwlabel(bw,n)" ); - return true; - } - - if ( !args(0).is_matrix_type() ) { - error( "bwlabel: matrix expected for first argument" ); - return true; - } - - if ( args.length() == 2 ) { - if ( !args(1).is_real_scalar() ) { - error( "bwlabel: expecting real scalar for second argument" ); - return true; - } - int n = args(1).int_value(); - if ( n != 4 && n != 6 && n != 8 ) { - error( "bwlabel: in bwlabel(BW,n) n must be in {4,6,8}" ); - return true; - } - } - - return false; - -} - - -static int find( int set[], int x ) -{ - int r = x; - while ( set[r] != r ) - r = set[r]; - return r; -} -
deleted file mode 100644 --- a/bwlabel.m +++ /dev/null @@ -1,231 +0,0 @@ -## Copyright (C) 2000 Etienne Grossmann -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## [im2,npix,bb] = bwlabel(im, mins, maxs, verbose) -## -## Find the connected regions of an image. -## -## im : RxC 0-1 matrix -## -## im2 : RxC int matrix in which the connected regions of im have been -## numbered. 4-neighborhoods are considered. -## -## npix : 1xQ int number of pixel in each region -## -## bb : 4xQ int bounding boxes of the regions. Rows are minrow, -## maxrow, mincol, maxcol. -## -## Options : -## -## mins : Minimum size of the regions (set to zero for no minimum) -## maxs : Maximum size of the regions (set to zero for no maximum) -## verbose : Level of output comments in range 0 to 2. -## - -## Author: Etienne Grossmann <etienne@cs.uky.edu> -## Last modified: July 2002 -## - -## Modified by David Fletcher <david@megapico.co.uk> to avoid artificially -## separate regions which actually touch (as indicated when "prudent" is set) -## through addition of lrow update within loop over touching regions. Also -## removed "sayif" function references, and call to read_options. Enabled -## options, setting of output verbosity. "Prudent" is left in place, but -## should no longer find any errors. - -function [im2,npix,bb] = bwlabel(im, mins, maxs, verbose) - - if (nargin == 1) - mins = 0; - maxs = 0; - prudent = 1; - verbose = 0; - elseif (nargin == 2) - maxs = 0; - prudent = 1; - verbose = 0; - elseif (nargin == 3) - prudent = 1; - verbose = 0; - elseif ((nargin == 4) && (verbose >= 0) && (verbose <= 2)) - prudent = 1; - else - usage ("bwlabel2(im, mins, maxs, verbose)"); - endif - -if any(im(:)&im(:)!=1), - printf("bwlabel : im is not binary\n"); - return -end - - -[R,C]=size(im); -tr = 0 ; - # Loop as little as possible -if R<C, tr = 1; im = im' ; [R,C]=size(im); end - -gsize = 100 ; # Predicted number of slices - -im2 = zeros(R,C); - # find horizontal up/down going edges -imup = max(im2, diff([zeros(1,C);im])) ; -imdo = -min(im2, diff([im;zeros(1,C)])) ; - -im2 = ones(R,C); -###################################################################### -## Find connected regions ############################################ - -rc = 1 ; # Counter of region slices - -rnum = ones(1,gsize); # List of labels of each slice -npix = zeros(1,gsize); # Sizes of regions (actual size is in - # region's first slice) -bb = zeros(4,gsize); # Bounding boxes - -if (verbose >= 1) printf("bwlabel : There will be %i loops ... \n%5i ",C,0) ; endif; - -lrow = zeros(R,1); # Last treated image column - -for i=1:C, - t1 = find(imup(:,i)) ; - t2 = find(imdo(:,i)) ; - - nrow = zeros(R,1); # Next row - - for j = 1:rows(t1(:)) , # Loop over slices of i'th column - - rc++ ; # rc = number of current slice. - im2(t1(j):t2(j),i) = rc ; - # Slices from previous column that touch - # this slice. - rr = create_set(lrow(t1(j):t2(j))) ; - if !isempty(rr) && !rr(1), rr = rr(2:length(rr)) ; end - - if rc>size(rnum,2), # Get more space (uncertain effect on - # speed; avoids resizing rnum and npix) - tmp = 2*(ceil(C*rc/i)-rc+1+rows(t1(:))-j) ; - if (verbose == 2) printf("bwlabel : (i=%i) Foreseeing %i more regions\n",i,tmp); endif; - rnum = [ rnum, ones(1,tmp) ] ; - npix = [ npix,zeros(1,tmp) ] ; - bb = [ bb,zeros(4,tmp) ] ; - end - - if isempty(rr), # New region - if (verbose == 2) printf("bwlabel : creating region %i\n",rc); endif; - - r0 = rc ; # r0 = number of the region - - bb(1,r0) = t1(j) ; - bb(2,r0) = t2(j) ; - bb(3:4,r0) = i ; - - else # Add to already existing region ##### - - r0 = rnum(rr(1)) ; - [i, j, r0]; - - bb(1,r0) = min(bb(1,r0),t1(j)) ; - bb(2,r0) = max(bb(2,r0),t2(j)) ; - bb(4,r0) = i ; - - # Touches region r0 - if (verbose == 2) printf("bwlabel : adding to region %i\n",r0); endif; - - # Touches other regions too - for k = rr(find(rr!=r0)), # Loop over other touching regions, that - # should be merged to the first. - if (verbose == 2) printf("bwlabel : merging regions %i and %i\n",k,r0); endif; - rnum(find(rnum==k)) = r0 ; - lrow(find(lrow==k)) = r0 ; ##Update lrow for next comparsion loop - npix(r0) = npix(r0) + npix(k) ; - bb([1,3],r0) = min(bb([1,3],r0)',bb([1,3],k)')' ; - bb([2,4],r0) = max(bb([2,4],r0)',bb([2,4],k)')' ; - end - - end # End of add to already existing region - ## if r0==259 && i==39,"r0==259",keyboard;end - rnum(rc) = r0 ; - - npix(r0) = npix(r0) + 1+t2(j)-t1(j) ; - - nrow(t1(j):t2(j)) = r0 ; - end # End of looping over slices - lrow = nrow ; - if (verbose >= 1) - printf("."); - if (!rem(i,70) && i<C) printf("\n%5i ",i); end - end -end # End of looping over columns - -if (verbose >= 1) printf("\n"); endif; - -keep = ones(1,rc) ; - -if mins, keep = keep & (npix(rnum(1:rc))>=mins) ; end -if maxs, keep = keep & (npix(rnum(1:rc))<=maxs) ; end -keep(1) = 1 ; -keep = find(keep) ; # Indices of slices to be kept - -foo = create_set(rnum(keep)) ; # Indices of regions to be kept -nr = prod(size(foo)) ; # Number of regions (including bg) -## lrow = zeros(1,nr) ; -tmp = zeros(1,rc) ; -tmp(foo) = 0:nr-1 ; - -bar = zeros(1,rc) ; -bar(keep) = tmp(rnum(keep)) ; - -## keyboard - -im2 = reshape(bar(im2),R,C) ; - -npix = npix(foo(2:nr)); -bb = bb(:,foo(2:nr)); - -if 0, # Draw bb on the image (will ruin - # coherence) - for i=1:nr-1, - im2([bb(1,i),bb(2,i)] ,bb(3,i):bb(4,i) ) = i ; - im2( bb(1,i):bb(2,i) ,[bb(3,i),bb(4,i)]) = i ; - end -end - -## keyboard -if prudent, - - if (verbose >= 1) printf("bwlabel : Checking coherence\n"); endif; - - hcontact = im2 & im2!=[im2(:,2:C),zeros(R,1)] & [im2(:,2:C),zeros(R,1)] ; - vcontact = im2 & im2!=[im2(2:R,:);zeros(1,C)] & [im2(2:R,:);zeros(1,C)] ; - ok = 1 ; - if (any(hcontact(:))) - if (verbose == 2) [x,y] = find(hcontact) endif; - ok = 0 ; - printf("bwlabel: Whoa! Found horizontally connected separated regions\n"); - end - if (any(vcontact(:))) - if (verbose == 2)[x,y] = find(vcontact) endif; - ok = 0 ; - printf("bwlabel: Whoa! Found vertically connected separated regions\n"); - end - if !ok, keyboard ; end -end - -## Eventually transpose result -if tr, - im2 = im2' ; - bb = bb([3,4,1,2],:); -end
deleted file mode 100644 --- a/bwmorph.m +++ /dev/null @@ -1,611 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{BW2} = } bwmorph (@var{BW},@var{operation}) -## @deftypefnx {Function File} {@var{BW2} = } bwmorph (@var{BW},@var{operation},@var{n}) -## Perform a morphological operation on a binary image -## -## BW2=bwmorph(BW,operation) performs a morphological operation -## specified by @var{operation} on binary image @var{BW}. All possible -## operations and their meaning are specified in a table below. -## -## BW2=bwmorph(BW,operation,n) performs a morphological operation -## @var{n} times. Keep in mind that it has no sense to apply some -## operations more than once, since some of them return the same result -## regardless how many iterations we request. Those return a warning if -## are called with n>1 and they compute the result for n=1. -## -## @var{n}>1 is actually used for the following operations: diag, -## dilate, erode, majority, shrink, skel, spur, thicken and thin. -## -## @table @code -## @item 'bothat' -## Performs a bottom hat operation, a closing operation (which is a -## dilation followed by an erosion) and finally substracts the original -## image. -## -## @item 'bridge' -## Performs a bridge operation. Sets a pixel to 1 if it has two nonzero -## neighbours which are not connected, so it "bridges" them. There are -## 119 3-by-3 patterns which trigger setting a pixel to 1. -## -## @item 'clean' -## Performs an isolated pixel remove operation. Sets a pixel to 0 if all -## of its eight-connected neighbours are 0. -## -## @item 'close' -## Performs closing operation, which is a dilation followed by erosion. -## It uses a ones(3) matrix as structuring element for both operations. -## -## @item 'diag' -## Performs a diagonal fill operation. Sets a pixel to 1 if that -## eliminates eight-connectivity of the background. -## -## @item 'dilate' -## Performs a dilation operation. It uses ones(3) as structuring element. -## -## @item 'erode' -## Performs an erosion operation. It uses ones(3) as structuring element. -## -## @item 'fill' -## Performs a interior fill operation. Sets a pixel to 1 if all -## four-connected pixels are 1. -## -## @item 'hbreak' -## Performs a H-break operation. Breaks (sets to 0) pixels that are -## H-connected. -## -## @item 'majority' -## Performs a majority black operation. Sets a pixel to 1 if five -## or more pixels in a 3-by-3 window are 1. If not it is set to 0. -## -## @item 'open' -## Performs an opening operation, which is an erosion followed by a -## dilation. It uses ones(3) as structuring element. -## -## @item 'remove' -## Performs a iterior pixel remove operation. Sets a pixel to 0 if -## all of its four-connected neighbours are 1. -## -## @item 'shrink' -## Performs a shrink operation. Sets pixels to 0 such that an object -## without holes erodes to a single pixel (set to 1) at or near its -## center of mass. An object with holes erodes to a connected ring lying -## midway between each hole and its nearest outer boundary. It preserves -## Euler number. -## -## @item 'skel' -## Performs a skeletonization operation. It calculates a "median axis -## skeleton" so that points of this skeleton are at the same distance of -## its nearby borders. It preserver Euler number. Please read -## compatibility notes for more info. -## -## It uses the same algorithm as skel-pratt but this could change for -## compatibility in the future. -## -## @item 'skel-lantuejol' -## Performs a skeletonization operation as described in Gonzalez & Woods -## "Digital Image Processing" pp 538-540. The text references Lantuejoul -## as authour of this algorithm. -## -## It has the beauty of being a clean and simple approach, but skeletons -## are thicker than they need to and, in addition, not guaranteed to be -## connected. -## -## This algorithm is iterative. It will be applied the minimum value of -## @var{n} times or number of iterations specified in algorithm -## description. It's most useful to run this algorithm with @code{n=Inf}. -## -## @item 'skel-pratt' -## Performs a skeletonization operation as described by William K. Pratt -## in "Digital Image Processing". -## -## @item 'spur' -## Performs a remove spur operation. It sets pixel to 0 if it has only -## one eight-connected pixel in its neighbourhood. -## -## @item 'thicken' -## Performs a thickening operation. This operation "thickens" objects -## avoiding their fusion. Its implemented as a thinning of the -## background. That is, thinning on negated image. Finally a diagonal -## fill operation is performed to avoid "eight-connecting" objects. -## -## @item 'thin' -## Performs a thinning operation. When n=Inf, thinning sets pixels to 0 -## such that an object without holes is converted to a stroke -## equidistant from its nearest outer boundaries. If the object has -## holes it creates a ring midway between each hole and its near outer -## boundary. This differ from shrink in that shrink converts objects -## without holes to a single pixels and thin to a stroke. It preserves -## Euler number. -## -## @item 'tophat' -## Performs a top hat operation, a opening operation (which is an -## erosion followed by a dilation) and finally substracts the original -## image. -## @end table -## -## Some useful concepts to understant operators: -## -## Operations are defined on 3-by-3 blocks of data, where the pixel in -## the center of the block. Those pixels are numerated as follows: -## -## @multitable @columnfractions 0.05 0.05 0.05 -## @item X3 @tab X2 @tab X1 -## @item X4 @tab X @tab X0 -## @item X5 @tab X6 @tab X7 -## @end multitable -## -## @strong{Neighbourhood definitions used in operation descriptions:} -## @table @code -## @item 'four-connected' -## It refers to pixels which are connected horizontally or vertically to -## X: X1, X3, X5 and X7. -## @item 'eight-connected' -## It refers to all pixels which are connected to X: X0, X1, X2, X3, X4, -## X5, X6 and X7. -## @end table -## -## @strong{Compatibility notes:} -## @table @code -## @item 'fill' -## Checking MATLAB behaviour is needed because its documentation doesn't -## make clear if it creates a black pixel if all eight-connected pixels -## are black or if four-connected suffice (as we do currently following -## Pratt's book). -## @item 'skel' -## Algorithm used here is described in Pratt's book. When applying it to -## the "circles" image in MATLAB documentation, results are not the -## same. Perhaps MATLAB uses Blum's algoritm (for further info please -## read comments in code). -## @item 'skel-pratt' -## This option is not available in MATLAB. -## @item 'skel-lantuejoul' -## This option is not available in MATLAB. -## @item 'thicken' -## This implementation also thickens image borders. This can easily be -## avoided i necessary. MATLAB documentation doesn't state how it behaves. -## @end table -## -## References: -## W. K. Pratt, "Digital Image Processing" -## Gonzalez and Woods, "Digital Image Processing" -## -## @end deftypefn -## @seealso dilate erode makelut applylut - - -## TODO: As soon as Octave doesn't segfault when assigning values to a -## TODO: bool matrix, remove all conversions from lut to logical and -## TODO: just create it as a logical from the beginning. - -## TODO: n behaviour should be tested in all cases for compatibility. - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function BW2 = bwmorph(BW, operation, n) - if(nargin<2 || nargin>3) - usage("BW2=bwmorph(BW, operation [,n])"); - endif - if(nargin<3) - n=1; - endif - if(n<0) - error("bwmorph: n should be > 0"); - elseif(n==0) ## we'll just return the same matrix (check this!) - BW2=BW; - endif - - ## post processing command - postcmd=""; - - switch(operation) - case('bothat') - se=ones(3); - BW2=erode(dilate(BW, se), se)-BW; - if(n>1) - ## TODO: check if ignoring n>1 is ok. Should I just ignore it - ## TODO: without a warning? - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('bridge') - ## see __bridge_lut_fun__ for rules - ## lut=makelut("__bridge_lut_fun__",3); - lut=logical([0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - BW2=applylut(BW, lut); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('clean') - ## BW(j,k)=X&&(X0||X1||...||X7) - ## lut=makelut(inline("x(2,2)&&any((x.*[1,1,1;1,0,1;1,1,1])(:))","x"),3); - ## which is the same as... - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - lut(17)=0; ## isolated to 0 - ## I'd prefer to create lut directly as a logical, but assigning a - ## value to a logical segfaults 2.1.57. We'll change it as soon as - ## it works. - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('close') - se=ones(3); - BW2=erode(dilate(BW, se), se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('diag') - ## see __diagonal_fill_lut_fun__ for rules - ## lut=makelut("__diagonal_fill_lut_fun__",3); - lut=logical([0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=applylut(BW, lut);"; - - - case('dilate') - cmd="BW2=dilate(BW, ones(3));"; - - case('erode') - cmd="BW2=erode(BW, ones(3));"; - - case('fill') - ## lut=makelut(inline("x(2,2)||(sum((x&[0,1,0;1,0,1;0,1,0])(:))==4)","x"),3); - ## which is the same as... - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - ## 16 exceptions - lut([171,172,175,176,235,236,239,240,427,428,431,432,491,492,495,496])=1; - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - - case('hbreak') - ## lut=makelut(inline("x(2,2)&&!(all(x==[1,1,1;0,1,0;1,1,1])||all(x==[1,0,1;1,1,1;1,0,1]))","x"),3); - ## which is the same as - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - lut([382,472])=0; ## the 2 exceptions - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('majority') - ## lut=makelut(inline("sum((x&ones(3,3))(:))>=5"),3); - lut=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=applylut(BW, lut);"; - - case('open') - se=ones(3); - BW2=dilate(erode(BW, se), se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('remove') - ## lut=makelut(inline("x(2,2)&&!(sum((x&[0,1,0;1,1,1;0,1,0])(:))==5)","x"),3); - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - ## 16 qualifying patterns - lut([187,188,191,192,251,252,255,256,443,444,447,448,507,508,511,512])=0; - BW2=applylut(BW, logical(lut)); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - case('shrink') - ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"S"); - lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;1;0;1;1;1;1;0;1;0;0;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); - ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'S')","m"),3); - lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;0;1;0;0;0;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;0;0;0;0;0;1;1;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; - - case({'skel','skel-pratt'}) - ## WARNING: Result doesn't look as MATLAB's sample. It has been - ## WARNING: coded following Pratt's guidelines for what he calls - ## WARNING: is a "reasonably close approximation". I couldn't find - ## WARNING: any bug. - ## WARNING: Perhaps MATLAB uses Blum's algorithm (which Pratt - ## WARNING: refers to) in: H. Blum, "A Transformation for - ## WARNING: Extracting New Descriptors of Shape", Symposium Models - ## WARNING: for Perception of Speech and Visual Form, W. - ## WARNING: Whaten-Dunn, Ed. MIT Press, Cambridge, MA, 1967. - - ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"K"); - lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;1;1;1;1;0]); - - ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'K')","m"),3); - lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;1;0;0;0;1;0;1;1;0;0;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;1;0;0;1;1;0;0;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;0;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;1;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; - postcmd="BW2=bwmorph(BW2,'bridge');"; - - case('skel-lantuejoul') - ## init values - se=ones(3,3); ## structuring element used everywhere - BW2=zeros(size(BW)); ## skeleton result - eBW=BW; ## eBW will hold k-times eroded BW - i=1; - while i<=n - if(!any(eBW)) ## if erosion result is 0-matrix then - break; ## we are over - endif - BW2|=eBW-dilate(erode(eBW, se), se); ## eBW - opening operation on eBW - ## contributes to skeleton - eBW=erode(eBW,se); - i++; - endwhile - return; ## no general loop in this case - - case('spur') - ## lut=makelut(inline("xor(x(2,2),(sum((x&[0,1,0;1,0,1;0,1,0])(:))==0)&&(sum((x&[1,0,1;0,0,0;1,0,1])(:))==1)&&x(2,2))","x"),3); - ## which is the same as - lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity - lut([18,21,81,273])=0; ## 4 qualifying patterns - lut=logical(lut); - cmd="BW2=applylut(BW, lut);"; - - case('thicken') - ## This implementation also "thickens" the border. To avoid this, - ## a simple solution could be to add a border of 1 to the reversed - ## image. - BW2=bwmorph(!BW,'thin',n); - BW2=bwmorph(BW2,'diag'); - return; - - case('thin') - ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"T"); - lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;0;1;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; - 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); - ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'T')","m"),3); - lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;0;1;0;1;1;0;0;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;0;0;0;0;1;1;0;0;1;0; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;1;0;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; - 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); - cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; - - - case('tophat') - se=ones(3); - BW2=BW-dilate(erode(BW, se), se); - if(n>1) - ## TODO: check if ignoring n>1 is ok. - disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); - endif - return; - - - otherwise - error("bwmorph: unknown operation type requested."); - endswitch - - ## we use this assignment because of the swap operation inside the - ## while. - BW2=BW; - - ## if it doesn't change we don't need to process it further - i=1; - while(i<=n) ## for wouldn't work because n can be Inf - [BW,BW2]=swap(BW,BW2); - eval(cmd); - if(all((BW2==BW)(:))) - break - endif - i+=1; - endwhile - - ## process post processing commands if needed - if(postcmd!="") - eval(postcmd); - endif - -endfunction - - -%!demo -%! bwmorph(ones(11),'shrink', Inf) -%! # Should return 0 matrix with 1 pixel set to 1 at (6,6) - -## TODO: code tests - - -## Test skel-lantuejoul using Gozalez&Woods example (fig 8.39) -%!shared slBW, rslBW -%! uint8(0); # fail for 2.1.57 or less instead of crashing later -%! slBW=logical(zeros(12,7)); -%! slBW(2,2)=true; -%! slBW(3:4,3:4)=true; -%! rslBW=slBW; -%! slBW(5:6,3:5)=true; -%! slBW(7:11,2:6)=true; -%! rslBW([6,7,9],4)=true; - -%!assert(bwmorph(slBW,'skel-lantuejoul',1),[rslBW(1:5,:);logical(zeros(7,7))]); -%!assert(bwmorph(slBW,'skel-lantuejoul',2),[rslBW(1:8,:);logical(zeros(4,7))]); -%!assert(bwmorph(slBW,'skel-lantuejoul',3),rslBW); -%!assert(bwmorph(slBW,'skel-lantuejoul',Inf),rslBW); - - -% -% $Log$ -% Revision 1.6 2004/09/16 02:14:40 pkienzle -% Use frivolous uint8() call to block tests for version 2.1.57 and earlier -% -% Revision 1.5 2004/09/15 20:36:57 jmones -% logical(1) => true -% -% Revision 1.4 2004/09/15 20:00:00 jmones -% Updated tests to match Gonzalez&Woods example -% -% Revision 1.3 2004/09/15 13:51:10 pkienzle -% Use logical in tests; reduce number of shared variables in tests. -% -% Revision 1.2 2004/09/01 22:35:47 jmones -% Added Lantuejoul skeletonizing algorithm from Gonzalez&Woods -% -% Revision 1.1 2004/08/15 19:47:04 jmones -% bwmorph added: Perform a morphological operation on a binary image -% -%
deleted file mode 100644 --- a/bwselect.m +++ /dev/null @@ -1,37 +0,0 @@ -function [imout, idx] = bwselect( im, cols, rows, connect ) -# BWSELECT: select connected regions in a binary image -# [imout, idx] = bwselect( im, cols, rows, connect ) -# -# im -> binary input image -# [cols,rows] -> vectors of starting points (x,y) -# connect -> connectedness 4 or 8. default is 8 -# imout -> the image of all objects in image im that overlap -# pixels in (cols,rows) -# idx -> index of pixels in imout - -# Copyright (C) 1999 Andy Adler -# This code has no warrany whatsoever. -# Do what you like with this code as long as you -# leave this copyright in place. -# -# $Id$ - -if nargin<4 - connect= 8; -end - -[jnk,idx]= bwfill( ~im, cols,rows, connect ); - -imout= zeros( size(jnk) ); -imout( idx ) = 1; - -# -# $Log$ -# Revision 1.1 2002/03/17 02:38:52 aadler -# fill and edge detection operators -# -# Revision 1.1 1999/06/08 17:06:01 aadler -# Initial revision -# -# -
deleted file mode 100644 --- a/cmpermute.m +++ /dev/null @@ -1,124 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{Y}, @var{newmap}] = } cmpermute (@var{X},@var{map}) -## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] = } cmpermute (@var{X},@var{map},@var{index}) -## Reorders colors in a colormap -## -## @code{[Y,newmap]=cmpermute(X,map)} rearranges colormap @var{map} -## randomly returning colormap @var{newmap} and generates indexed image -## @var{Y} so that it mantains correspondence between indices and the -## colormap from original indexed image @var{X} (both image and colormap -## pairs produce the same result). -## -## @code{[Y,newmap]=cmpermute(X,map,index)} behaves as described above -## but instead of sorting colors randomly, it uses @var{index} to define -## the order of the colors in the new colormap. -## -## @strong{Note:} @code{index} shouldn't have repeated elements, this -## function won't explicitly check this, but it will fail if it has. -## -## @end deftypefn - - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function [Y, newmap] = cmpermute(X, map, index) - switch(nargin) - case(2) - index=randperm(rows(map)); - case(3) - if(!isvector(index) || length(index)!=rows(map)) - error("cmpermute: invalid parameter index."); - endif - otherwise - usage("[Y, newmap] = cmpermute(X, map [, index])"); - endswitch - - ## new colormap - newmap=map(index,:); - - ## build reverse index - rindex = zeros(size(index)); - rindex(index) = 1:length(index); - - ## readapt indices - if(isa(X,"uint8")) - rindex=uint8(rindex-1); - ## 0-based indices - Y=rindex(double(X)+1); - else - Y=rindex(X); - endif -endfunction - - -%!demo -%! [Y,newmap]=cmpermute([1:4],hot(4),4:-1:1) -%! # colormap will be arranged in reverse order (so will image) - -%!shared X,map -%! X=magic(16); -%! [X,map]=cmunique(X); - -%!test # random permutation, 0-based index -%! [Y,newmap]=cmpermute(X,map); -%! # test we didn't lose colors -%! assert(sort(map),sortrows(newmap)); -%! # test if images are equal -%! assert(map(double(X)+1),newmap(double(Y)+1)); - -%!test # reverse map, 0-based index -%! [Y,newmap]=cmpermute(X,map,rows(map):-1:1); -%! # we expect a reversed colormap -%! assert(newmap(rows(newmap):-1:1,:),map); -%! # we expect reversed indices in image -%! assert(X,max(Y(:))-Y); - -%!shared X,map -%! X=magic(20); -%! [X,map]=cmunique(X); - -%!test # random permutation, 1-based index -%! [Y,newmap]=cmpermute(X,map); -%! # test we didn't lose colors -%! assert(sort(map),sortrows(newmap)); -%! # test if images are equal -%! assert(map(X),newmap(Y)); - -%!test # reverse map, 1-based index -%! [Y,newmap]=cmpermute(X,map,rows(map):-1:1); -%! # we expect a reversed colormap -%! assert(newmap(rows(newmap):-1:1,:),map); -%! # we expect reversed indices in image -%! assert(X,max(Y(:))+1-Y); - -% -% $Log$ -% Revision 1.4 2004/09/08 15:01:28 pkienzle -% Redo tests: reduce # of shared variables; force full range of uint8 -% -% Revision 1.3 2004/09/08 14:13:08 jmones -% Synchronized with cmunique. uint8 support added. Tests working for 2.1.58 -% -% Revision 1.2 2004/08/18 14:57:42 jmones -% speed improvement suggested by Paul Kienzle -% -% Revision 1.1 2004/08/17 19:18:42 jmones -% cmpermute added: Reorders colors in a colormap -% -%
deleted file mode 100644 --- a/cmunique.m +++ /dev/null @@ -1,203 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{Y}, @var{newmap}] = } cmunique (@var{X},@var{map}) -## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] = } cmunique (@var{RGB}) -## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] = } cmunique (@var{I}) -## Finds colormap with unique colors and corresponding image -## -## @code{[Y,newmap]=cmunique(X,map)} returns an indexed image @var{y} -## along with its associated colormap @var{newmap} equivalent (which -## produce the same image) to supplied @var{X} and its colormap -## @var{map}; but eliminating any repeated rows in colormap colors and -## adjusting indices in the image matrix as needed. -## -## @code{[Y,newmap]=cmunique(RGB)} returns an indexed image @var{y} -## along with its associated colormap @var{newmap} computed from a -## true-color image @var{RGB} (a m-by-n-by-3 array), where @var{newmap} -## is the smallest colormap possible (alhough it could be as long as -## number of pixels in image). -## -## @code{[Y,newmap]=cmunique(I)} returns an indexed image @var{y} -## along with its associated colormap @var{newmap} computed from a -## intensity image @var{I}, where @var{newmap} is the smallest -## colormap possible (alhough it could be as long as number of pixels -## in image). -## -## @strong{Notes:} -## -## @var{newmap} is always a @var{m}-by-3 matrix, even if input image is -## a intensity grey-scale image @var{I} (all three RGB planes are -## assigned the same value). -## -## @var{newmap} is always of class double. If we use a RGB or intensity -## image of class uint8 or uint16, the colors in the colormap will be of -## class double in the range [0,1] (they are divided by intmax("uint8") -## and intmax("uint16") respectively. -## -## @end deftypefn - - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function [Y, newmap] = cmunique(P1, P2) - if (nargin<1 || nargin>2) - usage("[Y, newmap] = cmunique(X, map), [Y, newmap] = cmunique(RGB), [Y, newmap] = cmunique(I)"); - endif - - - if(nargin==2) - ## (X, map) case - [newmap,i,j]=unique(P2,'rows'); ## calculate unique colormap - if(isa(P1,"double")) - Y=j(P1); ## find new indices - else - Y=j(double(P1)+1); ## find new indices - endif - else - switch(size(P1,3)) - case(1) - ## I case - [newmap,i,j]=unique(P1); ## calculate unique colormap - newmap=repmat(newmap,1,3); ## get a RGB colormap - Y=reshape(j,rows(P1),columns(P1)); ## Y is j reshaped - case(3) - ## RGB case - map=[P1(:,:,1)(:), P1(:,:,2)(:), P1(:,:,3)(:)]; ## build a map with all values - [newmap,i,j]=unique(map, 'rows'); ## calculate unique colormap - Y=reshape(j,rows(P1),columns(P1)); ## Y is j reshaped - otherwise - error("cmunique: first parameter is invalid."); - endswitch - - ## if image was uint8 or uint16 we have to convert newmap to [0,1] range - if(!isa(P1,"double")) - newmap=double(newmap)/double(intmax(class(P1))); - endif - endif - - if(rows(newmap)<=256) - ## convert Y to uint8 (0-based indices then) - Y=uint8(Y-1); - endif - - -endfunction - - -%!demo -%! [Y,newmap]=cmunique([1:4;5:8],[hot(4);hot(4)]) -%! # Both rows are equal since map maps colors to the same value -%! # cmunique will give the same indices to both - - -%!# This triggers invalid first parameter -%!error(cmunique(zeros(3,3,2))); - -%!# Check that output is uint8 in short colormaps -%!test -%! [Y,newmap]=cmunique([1:4;5:8], [hot(4);hot(4)]); -%! assert(Y,uint8([0:3;0:3])); -%! assert(newmap,hot(4)); - -%!# Check that output is double in bigger -%!test -%! [Y,newmap]=cmunique([1:300;301:600], [hot(300);hot(300)]); -%! assert(Y,[1:300;1:300]); -%! assert(newmap,hot(300)); - -%!# Check boundary case 256 -%!test -%! [Y,newmap]=cmunique([1:256;257:512], [hot(256);hot(256)]); -%! assert(Y,uint8([0:255;0:255])); -%! assert(newmap,hot(256)); - -%!# Check boundary case 257 -%!test -%! [Y,newmap]=cmunique([1:257;258:514], [hot(257);hot(257)]); -%! assert(Y,[1:257;1:257]); -%! assert(newmap,hot(257)); - -%!# Random RGB image -%!test -%! RGB=rand(10,10,3); -%! [Y,newmap]=cmunique(RGB); -%! assert(RGB(:,:,1),newmap(:,1)(Y+1)); -%! assert(RGB(:,:,2),newmap(:,2)(Y+1)); -%! assert(RGB(:,:,3),newmap(:,3)(Y+1)); - -%!# Random uint8 RGB image -%!test -%! RGB=uint8(rand(10,10,3)*255); -%! RGBd=double(RGB)/255; -%! [Y,newmap]=cmunique(RGB); -%! assert(RGBd(:,:,1),newmap(:,1)(Y+1)); -%! assert(RGBd(:,:,2),newmap(:,2)(Y+1)); -%! assert(RGBd(:,:,3),newmap(:,3)(Y+1)); - -%!# Random uint16 RGB image -%!test -%! RGB=uint16(rand(10,10,3)*65535); -%! RGBd=double(RGB)/65535; -%! [Y,newmap]=cmunique(RGB); -%! assert(RGBd(:,:,1),newmap(:,1)(Y+1)); -%! assert(RGBd(:,:,2),newmap(:,2)(Y+1)); -%! assert(RGBd(:,:,3),newmap(:,3)(Y+1)); - -%!# Random I image -%!test -%! I=rand(10,10); -%! [Y,newmap]=cmunique(I); -%! assert(I,newmap(:,1)(Y+1)); -%! assert(I,newmap(:,2)(Y+1)); -%! assert(I,newmap(:,3)(Y+1)); - -%!# Random uint8 I image -%!test -%! I=uint8(rand(10,10)*256); -%! Id=double(I)/255; -%! [Y,newmap]=cmunique(I); -%! assert(Id,newmap(:,1)(Y+1)); -%! assert(Id,newmap(:,2)(Y+1)); -%! assert(Id,newmap(:,3)(Y+1)); - -%!# Random uint16 I image -%!test -%! I=uint16(rand(10,10)*65535); -%! Id=double(I)/65535; -%! [Y,newmap]=cmunique(I); -%! assert(Id,newmap(:,1)(Y+1)); -%! assert(Id,newmap(:,2)(Y+1)); -%! assert(Id,newmap(:,3)(Y+1)); - -% -% $Log$ -% Revision 1.4 2004/09/08 16:06:31 jmones -% Solved problem with uint8 indexing and reduced tests on types (suggested by P. Kienzle) -% -% Revision 1.3 2004/09/03 17:07:26 jmones -% Support for uint8 and uint16 types added. -% -% Revision 1.2 2004/08/17 15:48:03 jmones -% Clarified expected data for RGB images in doc -% -% Revision 1.1 2004/08/17 15:45:40 jmones -% cmunique: Finds colormap with unique colors and corresponding image -% -% - -
deleted file mode 100644 --- a/col2im.m +++ /dev/null @@ -1,169 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{A} = } col2im (@var{B}, [@var{m},@var{n}], [@var{mm},@var{nn}], @var{block_type}) -## @deftypefnx {Function File} {@var{A} = } col2im (@var{B}, [@var{m},@var{n}], [@var{mm},@var{nn}]) -## Rearranges matrix columns into blocks -## -## @code{A=col2im(B,[m,n],[mm,nn],block_type)} rearranges columns of -## matrix @var{B} intro blocks in a way controlled by @var{block_type} -## param, which can take the following values: -## -## @table @code -## @item distinct -## It uses @var{m}-by-@var{n} distinct blocks (which are not -## overlapped), and are rearranged to form a @var{mm}-by-@var{nn} matrix -## @var{A}. @var{B}'s height must be @var{m}*@var{n} and @code{col2im} -## rearranges each column to a @var{m}-by-@var{n} block and uses them to -## fill the whole matrix in left-to-right and then up-to-down order. -## @item sliding -## Is uses @var{m}-by-@var{n} sliding blocks. It rearranges row vector -## @var{B} to a (@var{mm}-@var{m}+1)-by-(@var{nn}-@var{n}+1) matrix -## @var{A}. @var{B} must be a -## 1-by-(@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1). -## @end table -## -## @code{A=col2im(B,[m,n],[mm,nn])} takes @code{distinct} as a default -## value for @var{block_type}. -## -## @end deftypefn -## @seealso{im2col} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function A = col2im(B, sblock, sb, block_type) - if(nargin<3 || nargin>4) - usage("A=col2im(B, [m,n], [mm,nn] [, block_type])"); - endif - - if(nargin!=4) - block_type='sliding'; - endif - - ## common checks - if(!ismatrix(B)) - error("col2im: B should be a matrix (or vector)."); - endif - if(!isvector(sblock) || length(sblock)!=2) - error("col2im: expected [m,n] as second parameter."); - endif - if(!isvector(sb) || length(sb)!=2) - error("col2im: expected [mm,nn] as third parameter."); - endif - - m=sblock(1); - n=sblock(2); - mm=sb(1); - nn=sb(2); - - switch(block_type) - case('distinct') - if(rows(B)!=m*n) - error("col2im: B height must be m*n for 'distinct' block_type."); - endif - if(rem(mm,m)!=0) - error("col2im: mm should be multiple of m"); - endif - if(rem(nn,n)!=0) - error("col2im: nn should be multiple of n"); - endif - mt=mm/m; - nt=nn/n; - if(columns(B)<mt*nt) - error("col2im: B's width is too small (should be mm*nn/(m*m))."); - endif - c=1; - for i=1:mt - ## TODO: check if we can horzcat([],uint8([10;11])) in a - ## future Octave version > 2.1.58 in order to deuglify this! - r=reshape(B(:,c),m,n); - c+=1; - for j=2:nt - r=horzcat(r, reshape(B(:,c),m,n)); - c+=1; - endfor - if(i==1) ## this workarrounds a bug in ver<=2.1.57 cat implementation - A=r; - else - A=vertcat(A,r); - endif - endfor - - case('sliding') - if(!all(size(B)==[1,(mm-m+1)*(nn-n+1)])) - error("col2im: wrong B size. Should be 1-by-(mm-m+1)*(nn-n+1)."); - endif - A=reshape(B, mm-m+1, nn-n+1); - - otherwise - error("col2im: invalid block_type."); - endswitch - -endfunction - -%!demo -%! A=[1:10;11:20;21:30;31:40] -%! B=im2col(A,[2,5],'distinct') -%! C=col2im(B,[2,5],[4,10],'distinct') -%! # Divide A using distinct blocks and reverse operation - - -%!shared B, Ad -%! v=[1:10]'; -%! r=reshape(v,2,5); -%! B=[v, v+10, v+20, v+30, v+40, v+50]; -%! Ad=[r, r+10; r+20, r+30; r+40, r+50]; - -%!# bad m -%!error(col2im(B,[3,5],[6,10],'distinct')); - -%!# bad n -%!error(col2im(B,[2,3],[6,10],'distinct')); - -%!# bad mm -%!error(col2im(B,[2,5],[7,10],'distinct')); - -%!# bad nn -%!error(col2im(B,[2,5],[6,11],'distinct')); - -%!# bad block_type -%!error(col2im(B,[2,5],[6,10],'wrong_block_type')); - -%!# this should be ok -%!assert(col2im(B,[2,5],[6,10],'distinct'), Ad); - -%!# now sliding -%!assert(col2im(ones(1,(10-2+1)*(7-3+1)),[2,3],[10,7]), ones((10-2+1),(7-3+1))); -%!assert(col2im(ones(1,(10-2+1)*(7-3+1)),[2,3],[10,7],'sliding'), ones((10-2+1),(7-3+1))); - - -%!# disctint on uint8 -%!assert(col2im(uint8(B),[2,5],[6,10],'distinct'), uint8(Ad)); - -%!# now sliding on uint8 -%!assert(col2im(ones(1,(10-2+1)*(7-3+1),"uint8"),[2,3],[10,7]), ones((10-2+1),(7-3+1),"uint8")); - - -% -% $Log$ -% Revision 1.2 2004/09/03 17:57:42 jmones -% Added support for int* and uint* types -% -% Revision 1.1 2004/08/18 14:39:07 jmones -% im2col and col2im added -% -%
deleted file mode 100644 --- a/colfilt.m +++ /dev/null @@ -1,94 +0,0 @@ -## COLFILT Apply filter to matrix blocks -## colfilt(A,[r c],[m n],'sliding',f,...) -## For each r x c overlapping subblock of A, add a column in matrix C -## f(C,...) should return a row vector which is then reshaped into a -## a matrix of size A and returned. A is processed in chunks of size m x n. -## colfilt(A,[r c],[m n],'distinct',f,...) -## For each r x c non-overlapping subblock of A, add a column in matrix C -## f(C,...) should return a matrix of size C each column of which is -## placed back into the subblock from whence it came. A is processed -## in chunks of size m x n. -## -## The present version requires [m n], but for compatibility it should -## be optional. Use colfilt(A,[r c],size(A),...) -## -## The present version requires that [m n] divide size(A), but for -## compatibility it should work even if [m n] does not divide A. Use -## the following instead: -## [r c] = size(A); -## padA = zeros (m*ceil(r/m),n*ceil(c/n)); -## padA(1:r,1:c) = A; -## B = colfilt(padA,...); -## B = B(1:r,1:c); -## -## The present version does not handle 'distinct' - -## This software is granted to the public domain -## Author: Paul Kienzle <pkienzle@users.sf.net> - -function B = colfilt(A,filtsize,blksize,blktype,f,varargin) - - [m,n]=size(A); - r = filtsize(1); - c = filtsize(2); - mblock = blksize(1); - nblock = blksize(2); - - switch blktype - case 'sliding' - # pad with zeros - padm = (m+r-1); - padn = (n+c-1); - padA = zeros(padm, padn); - padA([1:m]+floor((r-1)/2),[1:n]+floor((c-1)/2)) = A; - padA = padA(:); - - # throw away old A to save memory. - B=A; clear A; - - # build the index vector - colidx = [0:r-1]'*ones(1,c) + padm*ones(r,1)*[0:c-1]; - offset = [1:mblock]'*ones(1,nblock) + padm*ones(mblock,1)*[0:nblock-1]; - idx = colidx(:)*ones(1,mblock*nblock) + ones(r*c,1)*offset(:)'; - clear colidx offset; - - # process the matrix, one block at a time - idxA = zeros(r*c,mblock*nblock); - tmp = zeros(mblock,nblock); - for i = 0:m/mblock-1 - for j = 0:n/nblock-1 - idxA(:) = padA(idx + (i*mblock + padm*j*nblock)); - tmp(:) = feval(f,idxA,varargin{:}); - B(1+i*mblock:(i+1)*mblock, 1+j*nblock:(j+1)*nblock) = tmp; - end - end - - case 'old-sliding' # processes the whole matrix at a time - padA = zeros(m+r-1,n+c-1); - padA([1:m]+floor(r/2),[1:n]+floor(c/2)) = A; - [padm,padn] = size(padA); - colidx = [0:r-1]'*ones(1,c) + padm*ones(r,1)*[0:c-1]; - offset = [1:m]'*ones(1,n) + padm*ones(m,1)*[0:n-1]; - idx = colidx(:)*ones(1,m*n) + ones(r*c,1)*offset(:)'; - idxA = zeros(r*c,m*n); - idxA(:) = padA(:)(idx); - B = zeros(size(A)); - B(:) = feval(f,idxA,varargin{:}); - case 'old-distinct' # processes the whole matrix at a time - if (r*floor(m/r) != m || c*floor(n/c) != n) - error("colfilt expected blocks to exactly fill A"); - endif - colidx = [0:r-1]'*ones(1,c) + m*ones(r,1)*[0:c-1]; - offset = [1:r:m]'*ones(1,n/c) + m*ones(m/r,1)*[0:c:n-1]; - idx =colidx(:)*ones(1,m*n/r/c) + ones(r*c,1)*offset(:)'; - idxA = zeros(r*c,m*n/r/c); - idxA(:) = A(:)(idx); - B = zeros(prod(size(A)),1); - B(idx) = feval(f,idxA,varargin{:}); - B = reshape(B,size(A)); - endswitch -endfunction - -%!test -%! A = reshape(1:36,6,6); -%! assert(colfilt(A,[2,2],[3,3],'sliding','sum'), conv2(A,ones(2),'same'));
deleted file mode 100644 --- a/colorgradient.m +++ /dev/null @@ -1,52 +0,0 @@ -## M = colorgradient(C,w,n) -## Define a colour map which smoothly traverses the given colors. -## C contains the colours, one row per r,g,b value. -## w(i) is the relative length of the transition from colour i to colour i+1 -## in the entire gradient. The default is ones(rows(C)-1,1). -## n is the length of the colour map. The default is rows(colormap). -## -## E.g., -## colorgradient([0,0,1; 1,1,0; 1,0,0]) # blue -> yellow -> red -## x = linspace(0,1,200); -## imagesc(x(:,ones(30,1)))'; - -## This program is granted to the public domain. -## Author: Paul Kienzle <pkienzle@users.sf.net> - -function ret = colorgradient(C,w,n) - if nargin < 1 || nargin > 3 - usage("M = colorgradient(C,w,n)") - endif - - if nargin == 1 - n = rows(colormap); - w = ones(length(C)-1,1); - elseif nargin == 2 - if (length(w) == 1) - n = w; - w = ones(rows(C)-1,1); - else - n = rows(colormap); - endif - endif - - if (length(w)+1 != rows(C)) - error("must have one weight for each color interval"); - endif - - w = 1+round((n-1)*cumsum([0;w(:)])/sum(w)); - map = zeros(n,3); - for i=1:length(w)-1 - if (w(i) != w(i+1)) - map(w(i):w(i+1),1) = linspace(C(i,1),C(i+1,1),w(i+1)-w(i)+1)'; - map(w(i):w(i+1),2) = linspace(C(i,2),C(i+1,2),w(i+1)-w(i)+1)'; - map(w(i):w(i+1),3) = linspace(C(i,3),C(i+1,3),w(i+1)-w(i)+1)'; - endif - endfor - - if nargout == 0 - colormap(map); - else - ret = map; - endif -endfunction
deleted file mode 100644 --- a/configure.add +++ /dev/null @@ -1,56 +0,0 @@ - -if test -e main/image/NOINSTALL ; then - - dnl Not installing so don't test for libjpeg/libpng/libMagick++. - STATUS=none - -else - - AC_DEFINE(have_jpeg) - AC_CHECK_HEADER(jpeglib.h, have_jpeg=yes, have_jpeg=no) - if test $have_jpeg = yes ; then - OF_CHECK_LIB(jpeg, jpeg_std_error, have_jpeg=yes, have_jpeg=no) - if test $have_jpeg = no ; then - STATUS="libjpeg not found" - else - STATUS="jpeg" - AC_SUBST(DEFHAVE_JPEG) - DEFHAVE_JPEG="HAVE_JPEG=1" - fi - else - STATUS="jpeglib.h not found" - fi - - AC_DEFINE(have_png) - AC_CHECK_HEADER(png.h, have_png=yes, have_png=no) - if test $have_png = yes ; then - OF_CHECK_LIB(png, png_set_sig_bytes, have_png=yes, have_png=no) - if test $have_png = no ; then - STATUS="$STATUS, libpng not found" - else - STATUS="$STATUS, png" - AC_SUBST(DEFHAVE_PNG) - DEFHAVE_PNG="HAVE_PNG=1" - fi - else - STATUS="$STATUS, png.h not found" - fi - - AC_CHECK_PROG(HAVE_MAGICKXX, Magick++-config, yes) - if test $HAVE_MAGICKXX ; then - STATUS="$STATUS, ImageMagick++" - AC_SUBST(DEFHAVE_MAGICKXX) - DEFHAVE_MAGICKXX="HAVE_MAGICKXX=1" - else - STATUS="$STATUS, ImageMagick++ not found" - fi - - -fi - -dnl Append the status message to the global status message. This will -dnl be displayed at the end of configuration so that the user doesn't -dnl have to scan the list for critical details. - -STATUS_MSG="$STATUS_MSG - read/write image formats: $STATUS"
deleted file mode 100644 --- a/conndef.m +++ /dev/null @@ -1,106 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{conn} = } conndef (@var{num_dims}, @var{type}) -## Creates a connectivity array -## -## @code{conn=conndef(num_dims,type)} creates a connectivity array -## (@var{CONN}) of @var{num_dims} dimensions and which type is defined -## by @var{type} as follows: -## @table @code -## @item minimal -## Neighbours touch the central element on a (@var{num_dims}-1)-dimensional -## surface. -## @item maximal -## Neighbours touch the central element in any way. Equivalent to -## @code{ones(repmat(3,1,@var{num_dims}))}. -## @end table -## -## @end deftypefn - - - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function conn = conndef(num_dims,conntype) - if(nargin!=2) - usage("conn=conndef(num_dims, type)"); - endif - if(num_dims<=0) - error("conndef: num_dims must be > 0"); - endif - - if(strcmp(conntype,"minimal")) - if(num_dims==1) - conn=[1;1;1]; - elseif(num_dims==2) - conn=[0,1,0;1,1,1;0,1,0]; - else - conn=zeros(repmat(3,1,num_dims)); - idx={}; - idx{1}=1:3; - for i=2:num_dims - idx{i}=2; - endfor - conn(idx{:})=1; - for i=2:num_dims - idx{i-1}=2; - idx{i}=1:3; - conn(idx{:})=1; - endfor - endif - - elseif(strcmp(conntype,"maximal")) - if(num_dims==1) - conn=[1;1;1]; - else - conn=ones(repmat(3,1,num_dims)); - endif - else - error("conndef: invalid type parameter."); - endif - -endfunction - -%!demo -%! conndef(2,'minimal') -%! % Create a 2-D minimal connectivity array - -%!assert(conndef(1,'minimal'), [1;1;1]); - -%!assert(conndef(2,'minimal'), [0,1,0;1,1,1;0,1,0]); - -%!test -%! C=zeros(3,3); -%! C(2,2,1)=1; -%! C(2,2,3)=1; -%! C(:,:,2)=[0,1,0;1,1,1;0,1,0]; -%! assert(conndef(3,'minimal'), C); - -%!assert(conndef(1,'maximal'), ones(3,1)); -%!assert(conndef(2,'maximal'), ones(3,3)); -%!assert(conndef(3,'maximal'), ones(3,3,3)); -%!assert(conndef(4,'maximal'), ones(3,3,3,3)); - - - -% $Log$ -% Revision 1.2 2005/07/03 01:10:19 pkienzle -% Try to correct for missing newline at the end of the file -% -% Revision 1.1 2004/08/15 19:38:44 jmones -% conndef added: Creates a connectivity array
deleted file mode 100644 --- a/cool.m +++ /dev/null @@ -1,51 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} cool (@var{n}) -## Create color colormap. -## (cyan to magenta) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = cool (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("cool: argument must be a scalar"); - endif - else - usage ("cool (number)"); - endif - - if (number == 1) - map = [0, 1, 1]; - elseif (number > 1) - r = (0:number - 1)' ./ (number - 1); - g = 1 - r; - b = ones (number, 1); - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/copper.m +++ /dev/null @@ -1,52 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} copper (@var{n}) -## Create color colormap. -## (black to a light copper tone) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = copper (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("copper: argument must be a scalar"); - endif - else - usage ("copper (number)"); - endif - - if (number == 1) - map = [0, 0, 0]; - elseif (number > 1) - x = linspace (0, 1, number)'; - r = (x < 4/5) .* (5/4 * x) + (x >= 4/5); - g = 4/5 * x; - b = 1/2 * x; - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/cordflt2.cc +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (C) 2000 Teemu Ikonen -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include <octave/oct.h> - -#ifdef HAVE_OCTAVE_20 -typedef Matrix boolMatrix; -#define bool_matrix_value matrix_value -#endif - -#define SWAP(a, b) { SWAP_temp = (a); (a)=(b); (b) = SWAP_temp; } - -// Template function for comparison -// ET is the type of the matrix element -template <class ET> -inline bool compare(const ET a, const ET b) -{ - if(a > b) - return 1; - else - return 0; -} - -// Explicit template function for complex compare -template <> inline bool compare<Complex>(const Complex a, const Complex b) -{ - double anorm2 = a.real() * a.real() + a.imag() * a.imag(); - double bnorm2 = b.real() * b.real() + b.imag() * b.imag(); - - if( anorm2 > bnorm2 ) { - return 1; - } else { - return 0; - } -} - -// select nth largest member from the array values -// Partitioning algorithm, see Numerical recipes chap. 8.5 -template <class ET> -ET selnth(ET *vals, int len, int nth) -{ - ET SWAP_temp; - ET hinge; - int l, r, mid, i, j; - - l = 0; - r = len - 1; - for(;;) { - // if partition size is 1 or two, then sort and return - if(r <= l+1) { - if(r == l+1 && compare<ET>(vals[l], vals[r])) { - SWAP(vals[l], vals[r]); - } - return vals[nth]; - } else { - mid = (l+r) >> 1; - SWAP(vals[mid], vals[l+1]); - // choose median of l, mid, r to be the hinge element - // and set up sentinels in the borders (order l, l+1 and r) - if(compare<ET>(vals[l], vals[r])) { - SWAP(vals[l], vals[r]); - } - if(compare<ET>(vals[l+1], vals[r])) { - SWAP(vals[l+1], vals[r]); - } - if(compare<ET>(vals[l], vals[l+1])) { - SWAP(vals[l], vals[l+1]); - } - i = l+1; - j = r; - hinge = vals[l+1]; - for(;;) { - do i++; while(compare<ET>(hinge, vals[i])); - do j--; while(compare<ET>(vals[j], hinge)); - if(i > j) - break; - SWAP(vals[i], vals[j]); - } - vals[l+1] = vals[j]; - vals[j] = hinge; - if(j >= nth) - r = j - 1; - if(j <= nth) - l = i; - } - } -} - -// Template function for doing the actual filtering -// MT is the type of the matrix to be filtered (Matrix or ComplexMatrix) -// ET is the type of the element of the matrix (double or Complex) -template <class MT, class ET> -octave_value_list do_filtering(MT A, int nth, boolMatrix dom, MT S) -{ - int i, j, c, d; - - int len = 0; - for(j = 0; j < dom.columns(); j++) { - for(i = 0; i < dom.rows(); i++) { - if(dom.elem(i,j)) - len++; - } - } - if(nth > len - 1) { - warning("nth should be less than number of non-zero values in domain"); - warning("setting nth to largest possible value\n"); - nth = len - 1; - } - if(nth < 0) { - warning("nth should be non-negative, setting to 1\n"); - nth = 0; // nth is a c-index - } - - int rowoffset = (dom.columns() + 1)/2 - 1; - int coloffset = (dom.rows() + 1)/2 - 1; - - //outputs - octave_value_list out; - const int origx = A.columns() - dom.columns()+1; - const int origy = A.rows() - dom.rows()+1; - MT retval = MT(origy, origx); - - int *offsets = new int[len]; - ET *values = new ET[len]; - ET *adds = new ET[len]; - - c = 0; - d = A.rows(); - for(j = 0; j < dom.columns(); j++) { - for(i = 0; i < dom.rows(); i++) { - if(dom.elem(i,j)) { - offsets[c] = (i - coloffset) + (j - rowoffset)*d; - adds[c] = S.elem(i,j); - c++; - } - } - } - - ET *data = A.fortran_vec(); - int base = coloffset + A.rows()*rowoffset; - for(j = 0; j < retval.columns(); j++) { - for(i = 0; i < retval.rows(); i++) { - for(c = 0; c < len; c++) { - values[c] = data[base + offsets[c]] + adds[c]; - } - base++; - retval(i, j) = selnth(values, len, nth); - } - base += dom.rows() - 1; - } - - out(0) = octave_value(retval); - - return out; -} - -// instantiate template functions -template bool compare<double>(const double, const double); -template double selnth(double *, int, int); -template Complex selnth(Complex *, int, int); -template octave_value_list do_filtering<Matrix, double>(Matrix, int, boolMatrix, Matrix); -// g++ is broken, explicit instantiation of specialized template function -// confuses the compiler. -//template int compare<Complex>(const Complex, const Complex); -template octave_value_list do_filtering<ComplexMatrix, Complex>(ComplexMatrix, int, boolMatrix, ComplexMatrix); - -DEFUN_DLD(cordflt2, args, , -"function retval = cordflt2(A, nth, domain, S)\n\ -\n\ - Implementation of two-dimensional ordered filtering. User interface\n\ - in ordfilt2.m") -{ - if(args.length() != 4) { - print_usage (); - return octave_value_list(); - } - - // nth is an index to an array, thus - 1 - int nth = (int) (args(1).vector_value())(0) - 1; - boolMatrix dom = args(2).bool_matrix_value(); - - octave_value_list retval; - - if(args(0).is_real_matrix()) { - Matrix A = args(0).matrix_value(); - Matrix S = args(3).matrix_value(); - retval = do_filtering<Matrix, double>(A, nth, dom, S); - } - else if(args(0).is_complex_matrix()) { - ComplexMatrix A = args(0).complex_matrix_value(); - ComplexMatrix S = args(3).complex_matrix_value(); - retval = do_filtering<ComplexMatrix, Complex>(A, nth, dom, S); - } - else { - error("A should be real or complex matrix\n"); - return octave_value_list(); - } - - return retval; - -}
deleted file mode 100644 --- a/corr2.m +++ /dev/null @@ -1,42 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{r}= corr2 (@var{I},@var{J}) -## returns the correlation coefficient between @var{I} and @var{j}. -## @var{I,J} must be real type matrices or vectors of same size -## @end deftypefn - - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 01/08/2000 - -function r = corr2 (I, J) - - if !(nargin == 2) - usage ("corr2(I,J)"); - endif - - if !(is_matrix(I) && isreal(I) && is_matrix(J) && isreal(J)) - error("argument must be a real type matrix"); - endif - - if (size (I) != size (J)) - error("arguments must be of same size") - endif - - r = cov (I, J) / (std2(I)*std2(J)); -endfunction
deleted file mode 100644 --- a/dilate.m +++ /dev/null @@ -1,87 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{BW2} = } dilate (@var{BW1},@var{SE}) -## @deftypefnx {Function File} {@var{BW2} = } dilate (@var{BW1},@var{SE},@var{alg}) -## @deftypefnx {Function File} {@var{BW2} = } dilate (@var{BW1},@var{SE},...,@var{n}) -## Perform a dilation morphological operation on a binary image. -## -## BW2 = dilate(BW1, SE) returns a binary image with the result of a dilation -## operation on @var{BW1} using neighbour mask @var{SE}. -## -## For each point in @var{BW1}, dilate search its neighbours (which are -## defined by setting to 1 their in @var{SE}). If any of its neighbours -## is on (1), then pixel is set to 1. If all are off (0) then it is set to 0. -## -## Center of @var{SE} is calculated using floor((size(@var{SE})+1)/2). -## -## Pixels outside the image are considered to be 0. -## -## BW2 = dilate(BW1, SE, alg) returns the result of a dilation operation -## using algorithm @var{alg}. Only 'spatial' is implemented at the moment. -## -## BW2 = dilate(BW1, SE, ..., n) returns the result of @var{n} dilation -## operations on @var{BW1}. -## -## @end deftypefn -## @seealso{erode} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function BW2 = dilate(BW1, SE, a, b) - alg='spatial'; - n=1; - if (nargin < 1 || nargin > 4) - usage ("BW2 = dilate(BW1, SE [, alg] [, n])"); - endif - if nargin == 4 - alg=a; - n=b; - elseif nargin == 3 - if ischar(a) - alg=a; - else - n=a; - endif - endif - - if !strcmp(alg, 'spatial') - error("dilate: alg not implemented."); - endif - - # "Binarize" BW1, just in case image is not [1,0] - BW1=BW1!=0; - - for i=1:n - # create result matrix - BW1=filter2(SE,BW1)>0; - endfor - - BW2=BW1; -endfunction - -%!demo -%! dilate(eye(5),ones(2,2)) -%! % returns a thick diagonal. - - - -%!assert(dilate(eye(3),[1])==eye(3)); # using [1] as a mask returns the same value -%!assert(dilate(eye(3),[1,0,0])==[[0;0],eye(2);0,0,0]); -%!assert(dilate(eye(3),[1,0,0,0])==[[0;0],eye(2);0,0,0]); # test if center is correctly calculated on even masks - -
deleted file mode 100644 --- a/edge.m +++ /dev/null @@ -1,240 +0,0 @@ -function [imout, thresh] = edge( im, method, thresh, param2 ) -# EDGE: find image edges -# [imout, thresh] = edge( im, method, thresh, param2 ) -# -# OUTPUT -# imout -> output image -# thresh -> output thresholds -# -# INPUT -# im -> input image (greyscale) -# thresh -> threshold value (value is estimated if not given) -# -# The following methods are based on high pass filtering the image in -# two directions, calculating a combined edge weight from and then thresholding -# -# method = 'roberts' -# filt1= [1 0 ; 0 -1]; filt2= rot90( filt1 ) -# combine= sqrt( filt1^2 + filt2^2 ) -# method = 'sobel' -# filt1= [1 2 1;0 0 0;-1 -2 -1]; filt2= rot90( filt1 ) -# combine= sqrt( filt1^2 + filt2^2 ) -# method = 'prewitt' -# filt1= [1 1 1;0 0 0;-1 -1 -1]; filt2= rot90( filt1 ) -# combine= sqrt( filt1^2 + filt2^2 ) -# method = 'kirsh' -# filt1= [1 2 1;0 0 0;-1 -2 -1]; filt2 .. filt8 are 45 degree rotations of filt1 -# combine= max( filt1 ... filt8 ) -# -# methods based on filtering the image and finding zero crossings -# -# method = 'log' -> Laplacian of Gaussians -# param2 is the standard deviation of the filter, default is 2 -# method = 'zerocross' -> generic zero-crossing filter -# param2 is the user supplied filter -# -# method = 'andy' -> my idea -# A.Adler's idea (c) 1999. somewhat based on the canny method -# Step 1: Do a sobel edge detection and to generate an image at -# a high and low threshold -# Step 2: Edge extend all edges in the LT image by several pixels, -# in the vertical, horizontal, and 45degree directions. -# Combine these into edge extended (EE) image -# Step 3: Dilate the EE image by 1 step -# Step 4: Select all EE features that are connected to features in -# the HT image -# -# Parameters: -# param2(1)==0 or 4 or 8 -> perform x connected dilatation (step 3) -# param2(2) dilatation coeficient (threshold) in step 3 -# param2(3) length of edge extention convolution (step 2) -# param2(4) coeficient of extention convolution in step 2 -# defaults = [8 1 3 3] - -# Copyright (C) 1999 Andy Adler -# This code has no warrany whatsoever. -# Do what you like with this code as long as you -# leave this copyright in place. -# -# $Id$ - -[n,m]= size(im); -xx= 2:m-1; -yy= 2:n-1; - -if strcmp(method,'roberts') || strcmp(method,'sobel') || ... - strcmp(method,'prewitt') - - - if strcmp(method,'roberts') - filt= [1 0;0 -1]/4; tv= 6; - elseif strcmp(method,'sobel') - filt= [1 2 1;0 0 0; -1 -2 -1]/8; tv= 2; - elseif strcmp(method,'prewitt') - filt= [1 1 1;0 0 0; -1 -1 -1]/6; tv= 4; - end - - imo= conv2(im, rot90(filt), 'same').^2 + conv2(im, filt, 'same').^2; - -# check to see if the user supplied a threshold -# if not, calculate one in the same way as Matlab - - if nargin<3 - thresh= sqrt( tv* mean(mean( imo(yy,xx) )) ); - end - -# The filters are defined for sqrt(imo), but since we calculated imo, compare -# to thresh ^2 - - imout= ( imo >= thresh^2 ); - -# Thin the wide edges - xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; - ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; - imout(yy,xx)= imout(yy,xx) & ( xpeak | ypeak ); - -elseif strcmp(method,'kirsch') - - filt1= [1 2 1;0 0 0;-1 -2 -1]; fim1= conv2(im,filt1,'same'); - filt2= [2 1 0;1 0 -1;0 -1 -2]; fim2= conv2(im,filt2,'same'); - filt3= [1 0 -1;2 0 -2;1 0 -1]; fim3= conv2(im,filt3,'same'); - filt4= [0 1 2;-1 0 1;-2 -1 0]; fim4= conv2(im,filt4,'same'); - - imo= reshape(max([abs(fim1(:)) abs(fim2(:)) abs(fim3(:)) abs(fim4(:))]'),n,m); - - if nargin<3 - thresh= 2* mean(mean( imo(yy,xx) )) ; - end - - imout= imo >= thresh ; - -# Thin the wide edges - xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; - ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; - imout(yy,xx)= imout(yy,xx) & ( xpeak | ypeak ); - -elseif strcmp(method,'log') || strcmp(method,'zerocross') - - if strcmp(method,'log') - if nargin >= 4; sd= param2; - else sd= 2; - end - - sz= ceil(sd*3); - [x,y]= meshgrid( -sz:sz, -sz:sz ); - filt = exp( -( x.^2 + y.^2 )/2/sd^2 ) .* ... - ( x.^2 + y.^2 - 2*sd^2 ) / 2 / pi / sd^6 ; - else - filt = param2; - end - filt = filt - mean(filt(:)); - - imo= conv2(im, filt, 'same'); - - if nargin<3 || isempty( thresh ) - thresh= 0.75* mean(mean( abs(imo(yy,xx)) )) ; - end - - zcross= imo > 0; - yd_zc= diff( zcross ); - xd_zc= diff( zcross' )'; - yd_io= abs(diff( imo ) ) > thresh; - xd_io= abs(diff( imo')') > thresh; - -# doing it this way puts the transition at the <=0 point - xl= zeros(1,m); yl= zeros(n,1); - imout= [ ( yd_zc == 1 ) & yd_io ; xl] | ... - [xl; ( yd_zc == -1 ) & yd_io ] | ... - [ ( xd_zc == 1 ) & xd_io , yl] | ... - [yl, ( xd_zc == -1 ) & xd_io ]; - -elseif strcmp(method,'canny') - error("method canny not implemented"); - -elseif strcmp(method,'andy') - - filt= [1 2 1;0 0 0; -1 -2 -1]/8; tv= 2; - imo= conv2(im, rot90(filt), 'same').^2 + conv2(im, filt, 'same').^2; - if nargin<3 || thresh==[]; - thresh= sqrt( tv* mean(mean( imo(yy,xx) )) ); - end -# sum( imo(:)>thresh ) / prod(size(imo)) - dilate= [1 1 1;1 1 1;1 1 1]; tt= 1; sz=3; dt=3; - if nargin>=4 - # 0 or 4 or 8 connected dilation - if length(param2) > 0 - if param2(1)==4 ; dilate= [0 1 0;1 1 1;0 1 0]; - elseif param2(1)==0 ; dilate= 1; - end - end - # dilation threshold - if length(param2) > 2; tt= param2(2); end - # edge extention length - if length(param2) > 2; sz= param2(3); end - # edge extention threshold - if length(param2) > 3; dt= param2(4); end - - end - fobliq= [0 0 0 0 1;0 0 0 .5 .5;0 0 0 1 0;0 0 .5 .5 0;0 0 1 0 0; - 0 .5 .5 0 0;0 1 0 0 0;.5 .5 0 0 0;1 0 0 0 0]; - fobliq= fobliq( 5-sz:5+sz, 3-ceil(sz/2):3+ceil(sz/2) ); - - xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; - ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; - - imht= ( imo >= thresh^2 * 2); # high threshold image - imht(yy,xx)= imht(yy,xx) & ( xpeak | ypeak ); - imht([1,n],:)=0; imht(:,[1,m])=0; - -% imlt= ( imo >= thresh^2 / 2); # low threshold image - imlt= ( imo >= thresh^2 / 1); # low threshold image - imlt(yy,xx)= imlt(yy,xx) & ( xpeak | ypeak ); - imlt([1,n],:)=0; imlt(:,[1,m])=0; - -# now we edge extend the low thresh image in 4 directions - - imee= ( conv2( imlt, ones(2*sz+1,1) , 'same') > tt ) | ... - ( conv2( imlt, ones(1,2*sz+1) , 'same') > tt ) | ... - ( conv2( imlt, eye(2*sz+1) , 'same') > tt ) | ... - ( conv2( imlt, rot90(eye(2*sz+1)), 'same') > tt ) | ... - ( conv2( imlt, fobliq , 'same') > tt ) | ... - ( conv2( imlt, fobliq' , 'same') > tt ) | ... - ( conv2( imlt, rot90(fobliq) , 'same') > tt ) | ... - ( conv2( imlt, flipud(fobliq) , 'same') > tt ); -# imee(yy,xx)= conv2(imee(yy,xx),ones(3),'same') & ( xpeak | ypeak ); - imee= conv2(imee,dilate,'same') > dt; # - -% ff= find( imht==1 ); -% imout = bwselect( imee, rem(ff-1, n)+1, ceil(ff/n), 8); - imout = imee; - - -else - - error (['Method ' method ' is not recognized']); - -end - - - - -# -# $Log$ -# Revision 1.1 2002/03/17 02:38:52 aadler -# fill and edge detection operators -# -# Revision 1.4 2000/11/20 17:13:07 aadler -# works? -# -# Revision 1.3 1999/06/09 17:29:36 aadler -# implemented 'andy' mode edge detection -# -# Revision 1.2 1999/06/08 14:26:50 aadler -# zero-cross and LoG filters work -# -# Revision 1.1 1999/06/07 21:01:38 aadler -# Initial revision -# -# - -#
deleted file mode 100644 --- a/erode.m +++ /dev/null @@ -1,89 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{BW2} = } erode (@var{BW1},@var{SE}) -## @deftypefnx {Function File} {@var{BW2} = } erode (@var{BW1},@var{SE},@var{alg}) -## @deftypefnx {Function File} {@var{BW2} = } erode (@var{BW1},@var{SE},...,@var{n}) -## Perform an erosion morphological operation on a binary image. -## -## BW2 = erosion(BW1, SE) returns a binary image with the result of an erosion -## operation on @var{BW1} using neighbour mask @var{SE}. -## -## For each point in @var{BW1}, erode searchs its neighbours (which are -## defined by setting to 1 their in @var{SE}). If all neighbours -## are on (1), then pixel is set to 1. If any is off (0) then it is set to 0. -## -## Center of @var{SE} is calculated using floor((size(@var{SE})+1)/2). -## -## Pixels outside the image are considered to be 0. -## -## BW2 = erode(BW1, SE, alg) returns the result of a erosion operation -## using algorithm @var{alg}. Only 'spatial' is implemented at the moment. -## -## BW2 = erosion(BW1, SE, ..., n) returns the result of @var{n} erosion -## operations on @var{BW1}. -## -## @end deftypefn -## @seealso{dilate} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function BW2 = erode(BW1, SE, a, b) - alg='spatial'; - n=1; - if (nargin < 1 || nargin > 4) - usage ("BW2 = erode(BW1, SE [, alg] [, n])"); - endif - if nargin == 4 - alg=a; - n=b; - elseif nargin == 3 - if ischar(a) - alg=a; - else - n=a; - endif - endif - - if !strcmp(alg, 'spatial') - error("erode: alg not implemented."); - endif - - # count ones in mask - thr=sum(SE(:)); - - # "Binarize" BW1, just in case image is not [1,0] - BW1=BW1!=0; - - for i=1:n - # create result matrix - BW1=filter2(SE,BW1) == thr; - endfor - - BW2=BW1; -endfunction - -%!demo -%! erode(ones(5,5),ones(3,3)) -%! % creates a zeros border around ones. - - - -%!assert(erode([0,1,0;1,1,1;0,1,0],[0,0,0;0,0,1;0,1,1])==[1,0,0;0,0,0;0,0,0]); -%!assert(erode([0,1,0;1,1,1;0,1,0],[0,1;1,1])==[1,0,0;0,0,0;0,0,0]); - -
deleted file mode 100644 --- a/fftconv2.m +++ /dev/null @@ -1,134 +0,0 @@ -## Copyright (C) 2004 Stefan van der Walt <stefan@sun.ac.za> -## -## This program is free software; redistribution and use in source and -## binary forms, with or without modification, are permitted provided that -## the following conditions are met: -## -## 1. Redistributions of source code must retain the above copyright -## notice, this list of conditions and the following disclaimer. -## 2. Redistributions in binary form must reproduce the above copyright -## notice, this list of conditions and the following disclaimer in the -## documentation and/or other materials provided with the distribution. -## -## THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -## OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -## SUCH DAMAGE. - -## FFTCONV2 Convolve 2 dimensional signals using the FFT. -## -## usage: fftconv2(a, b[, shape]) -## fftconv2(v1, v2, a, shape) -## -## This method is faster but less accurate for large a,b. It -## also uses more memory. A small complex component will be -## introduced even if both a and b are real. -## -## see also: conv2 - -## Author: Stefan van der Walt <stefan@sun.ac.za> -## Date: 2004 - -function X = fftconv2(varargin) - if (nargin < 2) - usage("fftconv2(a,b[,shape]) or fftconv2(v1, v2, a, shape)") - endif - - shape = "full"; - rowcolumn = 0; - - if ((nargin > 2) && ismatrix(varargin{3})) - ## usage: fftconv2(v1, v2, a[, shape]) - - rowcolumn = 1; - v1 = varargin{1}(:)'; - v2 = varargin{2}(:); - orig_a = varargin{3}; - - if (nargin == 4) shape = varargin{4}; endif - else - ## usage: fftconv2(a, b[, shape]) - - a = varargin{1}; - b = varargin{2}; - if (nargin == 3) shape = varargin{3}; endif - - endif - - if (rowcolumn) - a = fftconv2(orig_a, v2); - b = v1; - endif - - ra = rows(a); - ca = columns(a); - rb = rows(b); - cb = columns(b); - - A = fft2(impad(a, [0 cb-1], [0 rb-1])); - B = fft2(impad(b, [0 ca-1], [0 ra-1])); - - X = ifft2(A.*B); - - if (rowcolumn) - rb = rows(v2); - ra = rows(orig_a); - cb = columns(v1); - ca = columns(orig_a); - endif - - if strcmp(shape,"same") - r_top = ceil((rb + 1) / 2); - c_top = ceil((cb + 1) / 2); - X = X(r_top:r_top + ra - 1, c_top:c_top + ca - 1); - elseif strcmp(shape, "valid") - X = X(rb:ra, cb:ca); - endif -endfunction - -%!# usage: fftconv2(a,b,[, shape]) -%!shared a,b -%! a = repmat(1:10, 5); -%! b = repmat(10:-1:3, 7); -%!assert(norm(fftconv2(a,b)-conv2(a,b)), 0, 1e6*eps) -%!assert(norm(fftconv2(b,a)-conv2(b,a)), 0, 1e6*eps) -%!assert(norm(fftconv2(a,b,'full')-conv2(a,b,'full')), 0, 1e6*eps) -%!assert(norm(fftconv2(b,a,'full')-conv2(b,a,'full')), 0, 1e6*eps) -%!assert(norm(fftconv2(a,b,'same')-conv2(a,b,'same')), 0, 1e6*eps) -%!assert(norm(fftconv2(b,a,'same')-conv2(b,a,'same')), 0, 1e6*eps) -%!assert(isempty(fftconv2(a,b,'valid'))); -%!assert(norm(fftconv2(b,a,'valid')-conv2(b,a,'valid')), 0, 1e6*eps) - -%!# usage: fftconv2(v1, v2, a[, shape]) -%!shared x,y,a -%! x = 1:4; y = 4:-1:1; a = repmat(1:10, 5); -%!assert(norm(fftconv2(x,y,a)-conv2(x,y,a)), 0, 1e6*eps) -%!assert(norm(fftconv2(x,y,a,'full')-conv2(x,y,a,'full')), 0, 1e6*eps) -%!assert(norm(fftconv2(x,y,a,'same')-conv2(x,y,a,'same')), 0, 1e6*eps) -%!assert(norm(fftconv2(x,y,a,'valid')-conv2(x,y,a,'valid')), 0, 1e6*eps) - -%!demo -%! ## Draw a cross -%! N = 100; -%! [x,y] = meshgrid(-N:N, -N:N); -%! z = 0*x; -%! z(N,1:2*N+1) = 1; z(1:2*N+1, N) = 1; -%! imshow(z); -%! -%! ## Draw a sinc blob -%! n = floor(N/10); -%! [x,y] = meshgrid(-n:n, -n:n); -%! b = x.^2 + y.^2; b = max(b(:)) - b; b = b / max(b(:)); -%! imshow(b); -%! -%! ## Convolve the cross with the blob -%! imshow(real(fftconv2(z, b, 'same')*N)) - -
deleted file mode 100644 --- a/flag.m +++ /dev/null @@ -1,50 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} flag (@var{n}) -## Create color colormap. -## (cycling through red, white, blue and black) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -## flag(number) gives a colormap consists of red, white, blue and black -## changing with each index - -function map = flag (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("flag: argument must be a scalar"); - endif - else - usage ("flag (number)"); - endif - - p = [1, 0, 0; 1, 1, 1; 0, 0, 1; 0, 0, 0]; - if (rem(number,4) == 0) - map=kron (ones (number / 4, 1), p); - else - map=[kron(ones (fix (number / 4), 1), p); p(1:rem (number, 4), :)]; - endif - -endfunction
deleted file mode 100644 --- a/graycomatrix.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* Copyright (C) 2004 Stefan van der Walt <stefan@sun.ac.za> - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include <octave/oct.h> - -DEFUN_DLD(graycomatrix, args, , "\ -\ -usage: P = graycomatrix(I, levels, distances, angles)\n\ -\n\ - Calculate the gray-level co-occurrence matrix P = f(i,j,d,theta)\n\ - of a gray-level image.\n\ -\n\ - P is a 4-dimensional matrix (histogram). The value P(i,j,d,theta)\n\ - is the number of times that gray-level j occurs at a distance 'd' and\n\ - at an angle 'theta' from gray-level j.\n\ -\n\ - 'I' is the input image which should contain integers in [0, levels-1],\n\ - where 'levels' indicate the number of gray-levels counted (typically\n\ - 256 for an 8-bit image). 'distances' and 'angles' are vectors of\n\ - the different distances and angles to use.\n" ) { - - // 4-dimensional histogram - // P = f(i, j, d, theta) where i and j are gray levels - // See Pattern Recognition Engineering (Morton Nadler & Eric P. Smith) - - octave_value_list retval; - - if (args.length() != 4) { - print_usage (); - // 'I' must be integer values [0, nr_of_levels-1] - - return retval; - } - - // Input arguments - Matrix I = args(0).matrix_value(); - int L = args(1).int_value(); - ColumnVector d = ColumnVector(args(2).vector_value()); - ColumnVector th = ColumnVector(args(3).vector_value()); - - if (error_state) { - print_usage (); - return retval; - } - - // Create output NDArray, P - dim_vector dim = dim_vector(); - dim.resize(4); - dim(0) = L; dim(1) = L; dim(2) = d.length(); dim(3) = th.length(); - NDArray P = NDArray(dim, 0); - - // Run through image - int d_max = (int)ceil(d.max()); - int cnt = 0; - - for (int r = 0; r < I.rows(); r++) { - for (int c = 0; c < I.columns(); c++) { - int i = (int)I(r,c); - - for (int d_idx = 0; d_idx < d.length(); d_idx++) { - int d_val = (int)d(d_idx); - for (int th_idx = 0; th_idx < th.length(); th_idx++) { - - double angle = th(th_idx); - - int row = r + (int)floor(cos(angle) * d_val + 0.5); - int col = c - (int)floor(sin(angle) * d_val + 0.5); - - if ( ( row >= 0 ) && ( row < I.rows() ) && - ( col >= 0 ) && ( col < I.cols() ) ) { - - int j = (int)I(row, col); - - if (i >= 0 && i < L && j >= 0 && j < L) { - Array<int> coord = Array<int> (4); - coord(0) = i; - coord(1) = j; - coord(2) = d_idx; - coord(3) = th_idx; - - P(coord)++; - } else { - warning("Image contains invalid gray-level! (%d, %d)", i, j); - } - } - - } - } - - } - } - - return octave_value(P); - -} - -/* - -%!shared a -%!test -%! a = [0 0 0 1 2; -%! 1 1 0 1 1; -%! 2 2 1 0 0; -%! 1 1 0 2 0; -%! 0 0 1 0 1]; -%! squeeze(graycomatrix(a, 3, 1, -pi/4)) == [4 2 0; -%! 2 3 2; -%! 1 2 0]; -%! -%!assert(size(graycomatrix(a, 3, 1:5, [0:3]*-pi/4)), [3, 3, 5, 4]) - -%!demo -%! -%! # Pattern Recognition Engineering (Nadler & Smith) -%! # Digital Image Processing (Gonzales & Woods), p. 668 -%! -%! a = [0 0 0 1 2; -%! 1 1 0 1 1; -%! 2 2 1 0 0; -%! 1 1 0 2 0; -%! 0 0 1 0 1]; -%! -%! graycomatrix(a, 3, 1, [0 1]*-pi/4) -%! - - -*/
deleted file mode 100644 --- a/grayslice.m +++ /dev/null @@ -1,78 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{X} =} grayslice (@var{I},@var{n}) -## @deftypefnx {Function File} {@var{X} =} grayslice (@var{I},@var{v}) -## creates an indexed image @var{X} from an intensitiy image @var{I} -## using multiple threshold levels. -## A scalar integer value @var{n} sets the levels to -## @example -## -## @group -## 1 2 n-1 -## -, -, ..., --- -## n n n -## @end group -## @end example -## -## X = grayslice(I,5); -## -## For irregular threshold values a real vector @var{v} can be used. -## The values must be in the range [0,1]. -## -## @group -## X = grayslice(I,[0.1,0.33,0.75,0.9]) -## @end group -## -## @end deftypefn -## @seealso{im2bw} - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 03. August 2000 - -function X = grayslice (I, v) - - if (nargin != 2) - usage ("grayslice(...) number of arguments must be 1 or 2"); - endif - - if (is_scalar(v) && (fix(v) == v)) - - v = (1:v - 1) / v; - - elseif (isvector(v)) - - if (any (v < 0) || (any (v > 1))) - error ("slice vector must be in range [0,1]") - endif - v = [0,v,1]; - else - - usage("second argument"); - - endif - - [r, c] = size (I); - [m, n] = sort ([v(:); I(:)]); - lx = length (v); - o = cumsum (n <= lx); - idx = o (find(n>lx)); - [m, n] = sort (I(:)); - [m, n] = sort (n); - X = reshape (idx(n), r, c); - -endfunction
deleted file mode 100644 --- a/histeq.m +++ /dev/null @@ -1,33 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{J}= histeq (@var{I},@var{n}) -## histogram equalization -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 08. August 2000 - -function J = histeq (I, n) - - [r,c] = size (I); - [X,map] = gray2ind(I); - [nn,xx] = imhist(I); - Icdf = ceil (n * cumsum (1/prod(size(I)) * nn)); - J = reshape(Icdf(X),r,c); - plot(Icdf,'b;;'); -endfunction
deleted file mode 100644 --- a/hot.m +++ /dev/null @@ -1,52 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} hot (@var{n}) -## Create color colormap. -## (black through dark red, red, orange, yellow to white) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = hot (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("hot: argument must be a scalar"); - endif - else - usage ("hot (number)"); - endif - - if (number == 1) - map = [0, 0, 0]; - elseif (number > 1) - x = linspace (0, 1, number)'; - r = (x < 2/5) .* (5/2 * x) + (x >= 2/5); - g = (x >= 2/5 & x < 4/5) .* (5/2 * x - 1) + (x >= 4/5); - b = (x >= 4/5) .* (5*x - 4); - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/houghtf.cc +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (C) 2004 Stefan van der Walt <stefan@sun.ac.za> - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include <octave/oct.h> - -DEFUN_DLD(houghtf, args, , "\ -\ -usage: [H, R] = houghtf(I[, angles])\n\ -\n\ - Calculate the straight line Hough transform of an image.\n\ -\n\ - The image, I, should be a binary image in [0,1]. The angles are given\n\ - in degrees and defaults to -90..90.\n\ -\n\ - H is the resulting transform, R the radial distances.\n\ -\n\ - See also: Digital Image Processing by Gonzales & Woods (2nd ed., p. 587)\n") { - - octave_value_list retval; - bool DEF_THETA = false; - - if (args.length() == 1) { - DEF_THETA = true; - } else if (args.length() != 2) { - print_usage (); - return retval; - } - - Matrix I = args(0).matrix_value(); - - ColumnVector thetas = ColumnVector(); - if (!DEF_THETA) { - thetas = ColumnVector(args(1).vector_value()); - } else { - thetas = ColumnVector(Range(-90,90).matrix_value()); - } - - if (error_state) { - print_usage (); - return retval; - } - - thetas = thetas / 180 * M_PI; - - int r = I.rows(); - int c = I.columns(); - - Matrix xMesh = Matrix(r, c); - Matrix yMesh = Matrix(r, c); - for (int m = 0; m < r; m++) { - for (int n = 0; n < c; n++) { - xMesh(m, n) = n+1; - yMesh(m, n) = m+1; - } - } - - Matrix size = Matrix(1, 2); - size(0) = r; size(1) = c; - double diag_length = sqrt( size.sumsq()(0) ); - int nr_bins = 2 * (int)ceil(diag_length) - 1; - RowVector bins = RowVector( Range(1, nr_bins).matrix_value() ) - ceil(nr_bins/2.); - - Matrix J = Matrix(bins.length(), 0); - - for (int i = 0; i < thetas.length(); i++) { - double theta = thetas(i); - ColumnVector rho_count = ColumnVector(bins.length(), 0); - - double cT = cos(theta); double sT = sin(theta); - for (int x = 0; x < r; x++) { - for (int y = 0; y < c; y++) { - if ( I(x, y) == 1 ) { - int rho = (int)floor( cT*x + sT*y + 0.5 ); - int bin = (int)(rho - bins(0)); - if ( (bin > 0) && (bin < bins.length()) ) { - rho_count( bin )++; - } - } - } - } - - J = J.append( rho_count ); - } - - retval.append(J); - retval.append(bins); - return retval; - -} - -/* -%!test -%! I = zeros(100, 100); -%! I(1,1) = 1; I(100,100) = 1; I(1,100) = 1; I(100, 1) = 1; I(50,50) = 1; -%! [J, R] = houghtf(I); J = J / max(J(:)); -%! assert(size(J) == [length(R) 181]); -%! - -%!demo -%! I = zeros(100, 150); -%! I(30,:) = 1; I(:, 65) = 1; I(35:45, 35:50) = 1; -%! for i = 1:90, I(i,i) = 1;endfor -%! I = imnoise(I, 'salt & pepper'); -%! imshow(I); -%! J = houghtf(I); J = J / max(J(:)); -%! imshow(J, bone(128), 'truesize'); - -*/
deleted file mode 100644 --- a/hsv.m +++ /dev/null @@ -1,49 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} hsv (@var{n}) -## Create color colormap. -## (red through yellow, green, cyan,blue,magenta to red) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = hsv (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("hsv: argument must be a scalar"); - endif - else - usage ("hsv (number)"); - endif - - if (number == 1) - map = [1, 0, 0]; - elseif (number > 1) - h = linspace (0, 1, number)'; - map = hsv2rgb ([h, ones(number, 1), ones(number, 1)]); - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/im2bw.m +++ /dev/null @@ -1,50 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{BW}= im2bw (@var{I},threshold) -## @deftypefnx {Function File} @var{BW}= im2bw (@var{X},@var{cmap},threshold) -## converts image data types to a black-white (binary) image. -## The treshold value should be in the range [0,1]. -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 19. March 2000 - -function BW = im2bw (img, a, b) - - if ( nargin < 2 || nargin > 3) - usage("im2bw(I) number of arguments must be 2 or 3"); - endif - - if (isgray (img)) - if (is_scalar (a)) - BW = (img >= a); - else - error ("threshold value must be scalar"); - endif - elseif (isind (img)) - if (is_matrix (a) && columns (a) == 3) - if (is_scalar (b)) - I = ind2gray (img, a); - BW = (I >= b); - endif - endif - else - error ("image matrix must be of index or intensity type"); - endif - -endfunction
deleted file mode 100644 --- a/im2col.m +++ /dev/null @@ -1,252 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{B} = } im2col (@var{A}, [@var{m},@var{n}], @var{block_type}) -## @deftypefnx {Function File} {@var{B} = } im2col (@var{A}, [@var{m},@var{n}]) -## @deftypefnx {Function File} {@var{B} = } im2col (@var{A}, 'indexed', ...) -## Rearranges image blocks into columns -## -## @code{B=im2col(A, [m, n], blocktype)} rearranges blocks in @var{A} -## into columns in a way that's determined by @var{block_type}, which -## can take the following values: -## -## @table @code -## @item distinct -## Rearranges each distinct @var{m}-by-@var{n} block in image @var{A} -## into a column of @var{B}. Blocks are scanned from left to right and -## the up to bottom in @var{A}, and columns are added to @var{B} from -## left to right. If @var{A}'s size is not multiple @var{m}-by-@var{n} -## it is padded. -## @item sliding -## Rearranges any @var{m}-by-@var{n} sliding block of @var{A} in a -## column of @var{B}, without any padding, so only sliding blocks which -## can be built using a full @var{m}-by-@var{n} neighbourhood are taken. -## In consequence, @var{B} has @var{m}*@var{n} rows and -## (@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1) columns (where @var{mm} and -## @var{nn} are the size of @var{A}). -## -## This case is thought to be used applying operations on columns of -## @var{B} (for instance using sum(:)), so that result is a -## 1-by-(@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1) vector, that is what -## the complementary function @code{col2im} expects. -## @end table -## -## @code{B=im2col(A,[m,n])} takes @code{distinct} as a default value for -## @var{block_type}. -## -## @code{B=im2col(A,'indexed',...)} will treat @var{A} as an indexed -## image, so it will pad using 1 if @var{A} is double. All other cases -## (incluing indexed matrices with uint8 and uint16 types and -## non-indexed images) will use 0 as padding value. -## -## Any padding needed in 'distinct' processing will be added at right -## and bottom edges of the image. -## -## @strong{Compatibility notes:} -## -## @itemize @bullet -## @item -## 'sliding' blocks are arranged into @var{B} in a top-down and -## left-right order. Since this isn't explicity described in MATLAB -## documentation, we ignore if it does it this way. It has been -## deduced because im2col implements inverse operation as a simple -## reshape (if we chose left to right and then up to down order we would -## had to transpose result). If you have MATLAB please check this -## issue. -## @item -## MATLAB docs say that when using @code{'indexed'}, padding with 0 is -## done for uint8 type. Since most functions do that too for uint16, we -## have chosen to use 0 also for uint16, even if documentation doesn't -## say it explicity, since it looks as an omission. -## @end itemize -## -## @end deftypefn -## @seealso{col2im} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function B = im2col(A, varargin) - if(nargin<2 || nargin>4) - usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); - endif - - ## check 'indexed' presence - indexed=false; - p=1; - if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) - if(nargin<3) - usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); - endif - indexed=true; - p+=1; - if(isa(A,"uint8") || isa(A,"uint16")) - padval=0; - else - padval=1; - endif - else - padval=0; - endif - - ## check [m,n] - if(!isvector(varargin{p})) - error("im2col: expected [m,n] but param is not a vector."); - endif - if(length(varargin{p})!=2) - error("im2col: expected [m,n] but param has wrong length."); - endif - m=varargin{p}(1); - n=varargin{p}(2); - p+=1; - - block_type='sliding'; - if(nargin>p) - ## we have block_type param - if(!ischar(varargin{p})) - error("im2col: invalid parameter block_type."); - endif - block_type=varargin{p}; - p+=1; - endif - - ## if we didn't have 'indexed' but had 4 parameters there's an error - if(nargin>p) - usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); - endif - - - ## common checks - if(!ismatrix(A)) - error("im2col: A should be a matrix (or vector)."); - endif - - switch(block_type) - case('distinct') - ## calc needed padding - sp=mod(-size(A)',[m;n]); - - if(any(sp)) - A=padarray(A,sp,padval,'post'); - endif - - ## iterate through all blocks - B=[]; - for i=1:m:size(A,1) ## up to bottom - for j=1:n:size(A,2) ## left to right - ## TODO: check if we can horzcat([],uint8([10;11])) in a - ## future Octave version > 2.1.58 - if(isempty(B)) - B=A(i:i+m-1,j:j+n-1)(:); - else - B=horzcat(B, A(i:i+m-1,j:j+n-1)(:)); - endif - endfor - endfor - - case('sliding') - if(indexed) - disp("WARNING: 'indexed' has no sense when using sliding."); - endif - if(m>size(A,1) || n>size(A,2)) - error("im2col: block size can't be greater than image size in sliding"); - endif - ## TODO: check if matlab uses top-down and left-right order - B=[]; - for j=1:1:size(A,2)-n+1 ## left to right - for i=1:1:size(A,1)-m+1 ## up to bottom - ## TODO: check if we can horzcat([],uint8([10;11])) in a - ## future Octave version > 2.1.58 - if(isempty(B)) - B=A(i:i+m-1,j:j+n-1)(:); - else - B=horzcat(B, A(i:i+m-1,j:j+n-1)(:)); - endif - endfor - endfor - - otherwise - error("im2col: invalid block_type."); - endswitch - -endfunction - -%!demo -%! A=[1:10;11:20;21:30;31:40] -%! B=im2col(A,[2,5],'distinct') -%! C=col2im(B,[2,5],[4,10],'distinct') -%! # Divide A using distinct blocks and reverse operation - -%!shared B, A, Bs, As, Ap, Bp0, Bp1 -%! v=[1:10]'; -%! r=reshape(v,2,5); -%! B=[v, v+10, v+20, v+30, v+40, v+50]; -%! A=[r, r+10; r+20, r+30; r+40, r+50]; -%! As=[1,2,3,4,5;6,7,8,9,10;11,12,13,14,15]; -%! b1=As(1:2,1:4)(:); -%! b2=As(2:3,1:4)(:); -%! b3=As(1:2,2:5)(:); -%! b4=As(2:3,2:5)(:); -%! Bs=[b1,b2,b3,b4]; -%! Ap=A(:,1:9); -%! Bp1=Bp0=B; -%! Bp0([9:10],[2,4,6])=0; -%! Bp1([9:10],[2,4,6])=1; - -%!# bad block_type -%!error(im2col(A,[2,5],'wrong_block_type')); - -%!# distinct -%!assert(im2col(A,[2,5],'distinct'), B); - -%!# padding -%!assert(im2col(Ap,[2,5],'distinct'), Bp0); -%!assert(im2col(Ap,'indexed',[2,5],'distinct'), Bp1); - -%!# now sliding -%!assert(im2col(As,[2,4]), Bs); -%!assert(im2col(As,[2,4],'sliding'), Bs); -%!assert(im2col(As,[3,5],'sliding'), As(:)); - -%!# disctint uint8 & uint16 -%!assert(im2col(uint8(A),[2,5],'distinct'), uint8(B)); -%!assert(im2col(uint16(A),[2,5],'distinct'), uint16(B)); - -%!# padding uint8 & uint16 (to 0 even in indexed case) -%!assert(im2col(uint8(Ap),[2,5],'distinct'), uint8(Bp0)); -%!assert(im2col(uint8(Ap),'indexed',[2,5],'distinct'), uint8(Bp0)); -%!assert(im2col(uint16(Ap),[2,5],'distinct'), uint16(Bp0)); -%!assert(im2col(uint16(Ap),'indexed',[2,5],'distinct'), uint16(Bp0)); - -%!# now sliding uint8 & uint16 -%!assert(im2col(uint8(As),[2,4],'sliding'), uint8(Bs)); -%!assert(im2col(uint16(As),[2,4],'sliding'), uint16(Bs)); - - - - -% -% $Log$ -% Revision 1.3 2005/09/08 02:00:17 pkienzle -% [for Bill Denney] isstr -> ischar -% -% Revision 1.2 2004/09/03 17:37:08 jmones -% Added support for int* and uint* types -% -% Revision 1.1 2004/08/18 14:39:07 jmones -% im2col and col2im added -% -%
deleted file mode 100644 --- a/imadjust.m +++ /dev/null @@ -1,353 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -## -## -## Based on old imadjust.m (GPL): -## Copyright (C) 1999,2000 Kai Habel - - -## -*- texinfo -*- -## @deftypefn {Function File} @var{J}= imadjust (@var{I}) -## @deftypefnx {Function File} @var{J}= imadjust (@var{I},[@var{low_in};@var{high_in}]) -## @deftypefnx {Function File} @var{J}= imadjust (@var{I},[@var{low_in};@var{high_in}],[@var{low_out};@var{high_out}]) -## @deftypefnx {Function File} @var{J}= imadjust (..., @var{gamma}) -## @deftypefnx {Function File} @var{newmap}= imadjust (@var{map}, ...) -## @deftypefnx {Function File} @var{RGB_out}= imadjust (@var{RGB}, ...) -## Adjust image or colormap values to a specified range -## -## @code{J=imadjust(I)} adjusts intensity image @var{I} values so that -## 1% of data on lower and higher values (2% in total) of the image is -## saturated; choosing for that the corresponding lower and higher -## bounds (using @code{stretchlim}) and mapping them to 0 and 1. @var{J} -## is an image of the same size as @var{I} which contains mapped values. -## This is equivalent to @code{imadjust(I,stretchlim(I))}. -## -## @code{J=imadjust(I,[low_in;high_in])} behaves as described but uses -## @var{low_in} and @var{high_in} values instead of calculating them. It -## maps those values to 0 and 1; saturates values lower than first limit -## to 0 and values higher than second to 1; and finally maps all values -## between limits linearly to a value between 0 and 1. If @code{[]} is -## passes as @code{[low_in;high_in]} value, then @code{[0;1]} is taken -## as a default value. -## -## @code{J=imadjust(I,[low_in;high_in],[low_out;high_out])} behaves as -## described but maps output values between @var{low_out} and -## @var{high_out} instead of 0 and 1. A default value @code{[]} can also -## be used for this parameter, which is taken as @code{[0;1]}. -## -## @code{J=imadjust(...,gamma)} takes, in addition of 3 parameters -## explained above, an extra parameter @var{gamma}, which specifies the -## shape of the mapping curve between input elements and output -## elements, which is linear (as taken if this parameter is omitted). If -## @var{gamma} is above 1, then function is weighted towards lower -## values, and if below 1, towards higher values. -## -## @code{newmap=imadjust(map,...)} applies a transformation to a -## colormap @var{map}, which output is @var{newmap}. This transformation -## is the same as explained above, just using a map instead of an image. -## @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and -## @var{gamma} can be scalars, in which case the same values are applied -## for all three color components of a map; or it can be 1-by-3 -## vectors, to define unique mappings for each component. -## -## @code{RGB_out=imadjust(RGB,...)} adjust RGB image @var{RGB} (a -## M-by-N-by-3 array) the same way as specified in images and colormaps. -## Here too @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and -## @var{gamma} can be scalars or 1-by-3 matrices, to specify the same -## mapping for all planes, or unique mappings for each. -## -## The formula used to realize the mapping (if we omit saturation) is: -## -## @code{J = low_out + (high_out - low_out) .* ((I - low_in) / (high_in - low_in)) .^ gamma;} -## -## @strong{Compatibility notes:} -## -## @itemize @bullet -## @item -## Prior versions of imadjust allowed @code{[low_in; high_in]} and -## @code{[low_out; high_out]} to be row vectors. Compatibility with this -## behaviour has been keeped, although preferred form is vertical vector -## (since it extends nicely to 2-by-3 matrices for RGB images and -## colormaps). -## @item -## Previous version of imadjust, if @code{low_in>high_in} it "negated" output. -## Now it is negated if @code{low_out>high_out}, for compatibility with -## MATLAB. -## @item -## Class of @var{I} is not considered, so limit values are not -## modified depending on class of the image, just treated "as is". When -## Octave 2.1.58 is out, limits will be multiplied by 255 for uint8 -## images and by 65535 for uint16 as in MATLAB. -## @end itemize -## -## @end deftypefn -## @seealso{stretchlim, brighten} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -## TODO: When Octave 2.1.58 is out multiply indices if input argument is -## TODO: of class int* or uint*. - -function ret = imadjust (image, in, out, gamma) - - if (nargin < 1 || nargin > 4) - usage ("imadjust(...) number of arguments must be between 1 and 4"); - endif - - if (nargin < 4) - gamma = 1; ## default gamma - endif - - if !(ismatrix(image)) - error ("imadjust(image,...) first parameter must be a image matrix or colormap"); - endif - - if (nargin==1) - in=stretchlim(image); ## this saturates 1% on lower and 1% on - out=[0;1]; ## higher values - endif - - if (nargin==2) - out=[0;1]; ## default out - endif - - if !((ismatrix(in) || isempty(in)) && (ismatrix(out) || isempty(out)) ) - usage("imadjust(image,[low high],[bottom top],gamma)"); - endif - - if (isempty(in)) - in=[0;1]; ## default in - endif - - if (isempty(out)) - out=[0;1]; ## default out - endif - - simage=size(image); - if (length(simage)==3 && simage(3)==3) - ## image is rgb - [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); - - ## make room - ret=zeros(size(image)); - - ## process each plane - for i=1:3 - ret(:,:,i)=__imadjust_plane__(image(:,:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(1,i)); - endfor - - elseif (length(simage)==2) - if(simage(2)==3 && \ - (size(in)==[2,3] || size(out)==[2,3] || size(gamma)==[1,3]) ) - ## image is a colormap - [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); - - ret=[]; - ## process each color - for i=1:3 - ret=horzcat(ret,__imadjust_plane__(image(:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(i))); - endfor - - else - ## image is a intensity image - if( !isvector(in) || length(in)!=2 || !isvector(out) || length(out)!=2 || !isscalar(gamma) || (gamma<0) || (gamma==Inf) ) - error("imadjust: on an intensity image, in and out must be 2-by-1 and gamma a positive scalar."); - endif - ret=__imadjust_plane__(image,in(1),in(2),out(1),out(2),gamma); - endif - - else - error("imadjust: first parameter must be a colormap, an intensity image or a RGB image"); - endif -endfunction - - -## This does all the work. I has a plane; li and hi input low and high -## values; and lo and ho, output bottom and top values. -## Image negative is computed if ho<lo although nothing special is -## needed, since formula automatically handles it. -function ret=__imadjust_plane__(I, li, hi, lo, ho, gamma) - ret = (I < li) .* lo; - ret = ret + (I >= li & I < hi) .* (lo + (ho - lo) .* ((I - li) / (hi - li)) .^ gamma); - ret = ret + (I >= hi) .* ho; -endfunction - - -## Checks in, out and gamma to see if they are ok for colormap and RGB -## cases. -function [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma) - switch(size(in)) - case([2,3]) - ## ok! - case([2,1]) - in=repmat(in,1,3); - case([1,2]) ## Compatibility behaviour! - in=repmat(in',1,3); - otherwise - error("imadjust: in must be 2-by-3 or 2-by-1."); - endswitch - - switch(size(out)) - case([2,3]) - ## ok! - case([2,1]) - out=repmat(out,1,3); - case([1,2]) ## Compatibility behaviour! - out=repmat(out',1,3); - otherwise - error("imadjust: out must be 2-by-3 or 2-by-1."); - endswitch - - switch(size(gamma)) - case([1,3]) - ## ok! - case([1,1]) - gamma=repmat(gamma,1,3); - otherwise - error("imadjust: gamma must be a scalar or a 1-by-3 matrix."); - endswitch - - ## check gamma allowed range - if(!all((gamma>=0)&(gamma<Inf))) - error("imadjust: gamma values must be in the range [0,Inf]"); - endif - -endfunction - - -# bad arguments - -# bad images -%!error(imadjust("bad argument")); -%!error(imadjust(zeros(10,10,3,2))); -%!error(imadjust(zeros(10,10,4))); -%!error(imadjust("bad argument")); - -# bad 2d, 3d or 4th argument -%!error(imadjust([1:100],"bad argument",[0;1],1)); -%!error(imadjust([1:100],[0,1,1],[0;1],1)); -%!error(imadjust([1:100],[0;1],[0,1,1],1)); -%!error(imadjust([1:100],[0;1],[0;1],[0;1])); -%!error(imadjust([1:100],[0;1],[0;1],-1)); - -%!# 1% on each end saturated -%!assert(imadjust([1:100]),[0,linspace(0,1,98),1]); - -%!# test with only input arg -%!assert(sum(abs((imadjust(linspace(0,1,100),[1/99;98/99]) - \ -%! [0,linspace(0,1,98),1] )(:))) < 1e-10); - -%!# a test with input and output args -%!assert(imadjust([1:100],[50;90],[-50;-30]), \ -%! [-50*ones(1,49), linspace(-50,-30,90-50+1), -30*ones(1,10)]); - -%!# a test with input and output args in a row vector (Compatibility behaviour) -%!assert(imadjust([1:100],[50,90],[-50,-30]), \ -%! [-50*ones(1,49), linspace(-50,-30,90-50+1), -30*ones(1,10)]); - -%!# the previous test, "negated" -%!assert(imadjust([1:100],[50;90],[-30;-50]), \ -%! [-30*ones(1,49), linspace(-30,-50,90-50+1), -50*ones(1,10)]); - - -%!shared cm,cmn -%! cm=[[1:10]',[2:11]',[3:12]']; -%! cmn=([[1:10]',[2:11]',[3:12]']-1)/11; - -%!# a colormap -%!assert(imadjust(cmn,[0;1],[10;11]),cmn+10); - -%!# a colormap with params in row (Compatibility behaviour) -%!assert(imadjust(cmn,[0,1],[10,11]),cmn+10); - -%!# a colormap, different output on each -%!assert(imadjust(cmn,[0;1],[10,20,30;11,21,31]),cmn+repmat([10,20,30],10,1)); - -%!# a colormap, different input on each, we need increased tolerance for this test -%!assert(sum(abs((imadjust(cm,[2,4,6;7,9,11],[0;1]) - \ -%! [[0,linspace(0,1,6),1,1,1]', \ -%! [0,0,linspace(0,1,6),1,1]', \ -%! [0,0,0,linspace(0,1,6),1]'] \ -%! ))(:)) < 1e-10 \ -%! ); - -%!# a colormap, different input and output on each -%!assert(sum(abs((imadjust(cm,[2,4,6;7,9,11],[0,1,2;1,2,3]) - \ -%! [[0,linspace(0,1,6),1,1,1]', \ -%! [0,0,linspace(0,1,6),1,1]'+1, \ -%! [0,0,0,linspace(0,1,6),1]'+2] \ -%! ))(:)) < 1e-10 \ -%! ); - -%!# a colormap, different gamma, input and output on each -%!assert(sum(abs((imadjust(cm,[2,4,6;7,9,11],[0,1,2;1,2,3],[1,2,3]) - \ -%! [[0,linspace(0,1,6),1,1,1]', \ -%! [0,0,linspace(0,1,6).^2,1,1]'+1, \ -%! [0,0,0,linspace(0,1,6).^3,1]'+2] \ -%! )(:))) < 1e-10 \ -%! ); - - -%!shared iRGB,iRGBn,oRGB -%! iRGB=zeros(10,1,3); -%! iRGB(:,:,1)=[1:10]'; -%! iRGB(:,:,2)=[2:11]'; -%! iRGB(:,:,3)=[3:12]'; -%! iRGBn=(iRGB-1)/11; -%! oRGB=zeros(10,1,3); -%! oRGB(:,:,1)=[0,linspace(0,1,6),1,1,1]'; -%! oRGB(:,:,2)=[0,0,linspace(0,1,6),1,1]'; -%! oRGB(:,:,3)=[0,0,0,linspace(0,1,6),1]'; - -%!# a RGB image -%!assert(imadjust(iRGBn,[0;1],[10;11]),iRGBn+10); - -%!# a RGB image, params in row (compatibility behaviour) -%!assert(imadjust(iRGBn,[0,1],[10,11]),iRGBn+10); - -%!# a RGB, different output on each -%!test -%! t=iRGBn; -%! t(:,:,1)+=10; -%! t(:,:,2)+=20; -%! t(:,:,3)+=30; -%! assert(imadjust(iRGBn,[0;1],[10,20,30;11,21,31]),t); - - -%!# a RGB, different input on each, we need increased tolerance for this test -%!assert(sum(abs((imadjust(iRGB,[2,4,6;7,9,11],[0;1]) - oRGB)(:))) < 1e-10); - -%!# a RGB, different input and output on each -%!test -%! t=oRGB; -%! t(:,:,2)+=1; -%! t(:,:,3)+=2; -%! assert(sum(abs((imadjust(iRGB,[2,4,6;7,9,11],[0,1,2;1,2,3]) - t)(:))) < 1e-10); - -%!# a RGB, different gamma, input and output on each -%!test -%! t=oRGB; -%! t(:,:,2)=t(:,:,2).^2+1; -%! t(:,:,3)=t(:,:,3).^3+2; -%! assert(sum(abs((imadjust(iRGB,[2,4,6;7,9,11],[0,1,2;1,2,3],[1,2,3]) - t)(:))) < 1e-10); - - -% -% $Log$ -% Revision 1.3 2004/09/01 22:51:14 jmones -% Fully recoded: NDArray support, docs, tests, more compatible with MATLAB, changed copyright -% -%
deleted file mode 100644 --- a/imginfo.m +++ /dev/null @@ -1,52 +0,0 @@ -## Copyright (C) 2002 Etienne Grossmann. All rights reserved. -## -## This program is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## This is distributed in the hope that it will be useful, but WITHOUT -## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -## for more details. -## - -## [h,w] = imginfo (filename) - Get image size from file -## hw = imginfo (filename) -## -## filename : string : Name of image file -## -## h : 1 : Height of image, in pixels -## w : 1 : Width of image, in pixels -## or -## hw=[h,w] : 2 : Height and width of image -## -## NOTE : imginfo relies on the 'convert' program. - -## Author: Etienne Grossmann <etienne@cs.uky.edu> -## Last modified: Setembro 2002 - -function [h,w] = imginfo (fn) - -[status, res] = system(sprintf("convert -verbose '%s' /dev/null",fn),1); - -if status, - error (["imginfo : 'convert' exited with status %i ",\ - "and produced\n%s\n"],\ - status, res); -end - -res = res(index(res," ")+1:length(res)); - -i = index (res,"x"); -if ! i, error ("imginfo : Can't interpret string (i)\n%s\n", res); end - -j = index (res(i-1:-1:1)," "); -if j<2, error ("imginfo : Can't interpret string (j)\n%s\n", res); end -w = str2num (res(i-j:i-1)); - -k = index (res(i+1:length(res))," "); -if k<2, error ("imginfo : Can't interpret string (k)\n%s\n", res); end -h = str2num (res(i+1:i+k)); - -if nargout<2, h = [h,w]; end
deleted file mode 100644 --- a/imhist.m +++ /dev/null @@ -1,72 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} imhist (@var{I},@var{n}) -## @deftypefnx {Function File} {} imhist (@var{I}) -## @deftypefnx {Function File} {} imhist (@var{X},@var{cmap}) -## @deftypefnx {Function File} {[@var{n,x}] = } imhist (...) -## Shows the histogram of an image using hist -## @end deftypefn -## @seealso{hist} - -## Author: Kai Habel <kai.habel@gmx.de> -## July 2000 : Paul Kienzle code simplification for hist() call. - -function [varargout] = imhist (I, b) - - if (nargin < 1 || nargin > 2) - usage("imhist(image,n)"); - endif - - b_is_colormap = 0; - - if (nargin == 2) - if (is_matrix (b)) - b_is_colormap = (columns (b) == 3); - endif - endif - - if (b_is_colormap) - ## assuming I is an indexed image - ## b is colormap - max_idx = max (max (I)); - bins = rows (b); - if (max_idx > bins) - warning ("largest index exceedes length of colormap"); - endif - else - ## assuming I is an intensity image - ## b is number of bins - if (nargin == 1) - bins = 256; - else - bins = b; - endif - - ## scale image to range [0,1] - I = mat2gray (I); - endif - - if (nargout == 2) - [nn,xx] = hist (I(:), bins); - vr_val_cnt = 1; varargout{vr_val_cnt++} = nn; - varargout{vr_val_cnt++} = xx; - else - hist (I(:), bins); - endif - -endfunction
deleted file mode 100644 --- a/imnoise.m +++ /dev/null @@ -1,72 +0,0 @@ -## Copyright (C) 2000 Paul Kienzle -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## usage: B = imnoise (A, type) -## -## Adds noise to image in A. -## -## imnoise (A, 'gaussian' [, mean [, var]]) -## additive gaussian noise: A = A + noise -## defaults to mean=0, var=0.01 -## -## imnoise (A, 'salt & pepper' [, density]) -## lost pixels: A = 0 or 1 for density*100% of the pixels -## defaults to density=0.05, or 5% -## -## imnoise (A, 'speckle' [, var]) -## multiplicative gaussian noise: A = A + A*noise -## defaults to var=0.04 - -## Modified: Stefan van der Walt <stefan@sun.ac.za>, 2004-02-24 - -function A = imnoise(A, stype, a, b) - - if (nargin < 2 || nargin > 4 || !is_matrix(A) || !ischar(stype)) - usage("B = imnoise(A, type, parameters, ...)"); - endif - - valid = (min(A(:)) >= 0 && max(A(:)) <= 1); - - stype = tolower(stype); - if (strcmp(stype, 'gaussian')) - if (nargin < 3), a = 0.0; endif - if (nargin < 4), b = 0.01; endif - A = A + (a + randn(size(A)) * sqrt(b)); - ## Variance of Gaussian data with mean 0 is E[X^2] - elseif (strcmp(stype, 'salt & pepper')) - if (nargin < 3), a = 0.05; endif - noise = rand(size(A)); - A(noise <= a/2) = 0; - A(noise >= 1-a/2) = 1; - elseif (strcmp(stype, 'speckle')) - if (nargin < 3), a = 0.04; endif - A = A .* (1 + randn(size(A))*sqrt(a)); - else - error("imnoise: use type 'gaussian', 'salt & pepper', or 'speckle'"); - endif - - if valid - A(A>1) = 1; - A(A<0) = 0; - else - warning("Image should be in [0,1]"); - endif - -endfunction - -%!assert(var(imnoise(ones(10)/2,'gaussian')(:)),0.01,0.005) # probabilistic -%!assert(length(find(imnoise(ones(10)/2,'salt & pepper')~=0.5)),5,10) # probabilistic -%!assert(var(imnoise(ones(10)/2,'speckle')(:)),0.01,0.005) # probabilistic
deleted file mode 100644 --- a/impad.m +++ /dev/null @@ -1,142 +0,0 @@ -## Copyright (C) 2000 Teemu Ikonen -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - -## -*- texinfo -*- -## @deftypefn {Function File} {} impad(@var{A}, @var{xpad}, @var{ypad}, [@var{padding}, [@var{const}]]) -## Pad (augment) a matrix for application of image processing algorithms. -## -## Pads the input image @var{A} with @var{xpad}(1) elements from left, -## @var{xpad}(2), elements from right, @var{ypad}(1) elements from above -## and @var{ypad}(2) elements from below. -## Values of padding elements are determined from the optional arguments -## @var{padding} and @var{const}. @var{padding} is one of -## -## @table @samp -## @item "zeros" -## pad with zeros (default) -## -## @item "ones" -## pad with ones -## -## @item "constant" -## pad with a value obtained from the optional fifth argument const -## -## @item "symmetric" -## pad with values obtained from @var{A} so that the padded image mirrors -## @var{A} starting from edges of @var{A} -## -## @item "reflect" -## same as symmetric, but the edge rows and columns are not used in the padding -## -## @item "replicate" -## pad with values obtained from A so that the padded image -## repeates itself in two dimensions -## -## @end table -## @end deftypefn - -## Author: Teemu Ikonen <tpikonen@pcu.helsinki.fi> -## Created: 5.5.2000 -## Keywords: padding image processing - -## A nice test matrix for padding: -## A = 10*[1:5]' * ones(1,5) + ones(5,1)*[1:5] - -function retval = impad(A, xpad, ypad, padding, const) - -try empty_list_elements_ok_save = empty_list_elements_ok; -catch empty_list_elements_ok_save = 0; -end -try warn_empty_list_elements_save = warn_empty_list_elements; -catch warn_empty_list_elements_save = 0; -end -unwind_protect - -if nargin < 4, padding = "zeros"; endif -if nargin < 5, const = 1; endif -if isscalar(xpad), xpad(2) = xpad(1); endif -if isscalar(ypad), ypad(2) = ypad(1); endif - -origx = size(A,2); -origy = size(A,1); -retx = origx + xpad(1) + xpad(2); -rety = origy + ypad(1) + ypad(2); - -empty_list_elements_ok = 1; -warn_empty_list_elements = 0; - -if(strcmp(padding, "zeros")) - retval = zeros(rety,retx); - retval(ypad(1)+1 : ypad(1)+origy, xpad(1)+1 : xpad(1)+origx) = A; - elseif(strcmp(padding,"ones")) - retval = ones(rety,retx); - retval(ypad(1)+1 : ypad(1)+origy, xpad(1)+1 : xpad(1)+origx) = A; - elseif(strcmp(padding,"constant")) - retval = const.*ones(rety,retx); - retval(ypad(1)+1 : ypad(1)+origy, xpad(1)+1 : xpad(1)+origx) = A; - elseif(strcmp(padding,"replicate")) - y1 = origy-ypad(1)+1; - x1 = origx-xpad(1)+1; - if(y1 < 1 || x1 < 1 || ypad(2) > origy || xpad(2) > origx) - error("Too large padding for this padding type"); - else - yrange1 = y1 : origy; - yrange2 = 1 : ypad(2); - xrange1 = x1 : origx; - xrange2 = 1 : xpad(2); - retval = [ A(yrange1, xrange1), A(yrange1, :), A(yrange1, xrange2); - A(:, xrange1), A, A(:, xrange2); - A(yrange2, xrange1), A(yrange2, :), A(yrange2, xrange2) ]; - endif - elseif(strcmp(padding,"symmetric")) - y2 = origy-ypad(2)+1; - x2 = origx-xpad(2)+1; - if(ypad(1) > origy || xpad(1) > origx || y2 < 1 || x2 < 1) - error("Too large padding for this padding type"); - else - yrange1 = 1 : ypad(1); - yrange2 = y2 : origy; - xrange1 = 1 : xpad(1); - xrange2 = x2 : origx; - retval = [ fliplr(flipud(A(yrange1, xrange1))), flipud(A(yrange1, :)), fliplr(flipud(A(yrange1, xrange2))); - fliplr(A(:, xrange1)), A, fliplr(A(:, xrange2)); - fliplr(flipud(A(yrange2, xrange1))), flipud(A(yrange2, :)), fliplr(flipud(A(yrange2, xrange2))) ]; - endif - elseif(strcmp(padding,"reflect")) - y2 = origy-ypad(2); - x2 = origx-xpad(2); - if(ypad(1)+1 > origy || xpad(1)+1 > origx || y2 < 1 || x2 < 1) - error("Too large padding for this padding type"); - else - yrange1 = 2 : ypad(1)+1; - yrange2 = y2 : origy-1; - xrange1 = 2 : xpad(1)+1; - xrange2 = x2 : origx-1; - retval = [ fliplr(flipud(A(yrange1, xrange1))), flipud(A(yrange1, :)), fliplr(flipud(A(yrange1, xrange2))); - fliplr(A(:, xrange1)), A, fliplr(A(:, xrange2)); - fliplr(flipud(A(yrange2, xrange1))), flipud(A(yrange2, :)), fliplr(flipud(A(yrange2, xrange2))) ]; - endif - else - error("Unknown padding type"); -endif - -unwind_protect_cleanup - empty_list_elements_ok = empty_list_elements_ok_save; - warn_empty_list_elements = warn_empty_list_elements_save; -end_unwind_protect - -endfunction
deleted file mode 100644 --- a/imread.m +++ /dev/null @@ -1,159 +0,0 @@ -## Copyright (C) 2002 Andy Adler -## -## This program is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2, or (at your option) -## any later version. USE THIS SOFTWARE AT YOUR OWN RISK. - -## usage: I = imread(fname) -## -## Read images from various file formats. -## -## The size and numeric class of the output depends on the -## format of the image. A colour image is returned as an -## MxNx3 matrix. Grey-level and black-and-white images are -## of size MxN. -## The colour depth of the image determines the numeric -## class of the output: 'uint8' or 'uint16' for grey -## and colour, and 'logical' for black and white. -## -## Note: For image formats other than jpeg and png, the -## ImageMagick "convert" and "identify" utilities -## are needed. ImageMagick can be found at -## -## www.imagemagick.org -## - -## Author: Andy Adler -## -## Modified: Stefan van der Walt <stefan@sun.ac.za> -## Date: 24 January 2005 - -function varargout = imread(filename, varargin) - if (nargin != 1) - usage("I = imread(filename)") - endif - - if !isstr(filename) - error("imread: filename must be a string") - endif - - fn = file_in_path(IMAGE_PATH, filename); - if isempty(fn) - error("imread: cannot find %s", filename); - endif - - - [ig, ig, ext] = fileparts(fn); - ext = upper(ext); - - ## divert jpegs and pngs to "jpgread" and "pngread" - if ( file_in_loadpath("jpgread.oct") && - (strcmp(ext, ".JPG") || strcmp(ext, ".JPEG")) ) - varargout{1} = jpgread(fn); - break - endif - if ( file_in_loadpath("pngread.oct") && (strcmp(ext, ".PNG")) ) - varargout{1} = pngread(fn); - break - endif - - ## alternately, use imagemagick - if ( file_in_loadpath("__magick_read__.oct") ) - varargout{:} = __magick_read__(fn, varargin{:}); - break - endif - - [sys, ident] = system(sprintf('identify -verbose %s | grep -e "Red: " -e Type', - fn)); - if (sys != 0) - error("imread: error running ImageMagick's 'identify' on %s", fn) - endif - depth = re_grab("Red: ([[:digit:]]{1,2})", ident); - imtype = re_grab("Type: ([[:alpha:]]*)", ident); - - depth = str2num(depth); - if isempty(depth) || (pow2(nextpow2(depth)) != depth) - error("imread: invalid image depth %s", depth) - endif - - if !(strcmp(imtype, "Bilevel") || strcmp(imtype, "Grayscale") || - strcmp(imtype, "TrueColor")) - error("imread: unknown image type '%s'", imtype); - endif - - switch (imtype) - case("Bilevel") - fmt = "pgm"; - case("Grayscale") - fmt = "pgm"; - case("TrueColor") - fmt = "ppm"; - endswitch - - ## Why are pipes so slow? - ## cmd = sprintf("convert -flatten -strip %s %s:-", fn, fmt); - - tmpf = [tmpnam(), ".", fmt]; - cmd = sprintf("convert -flatten -strip +compress '%s' '%s' 2>/dev/null", - fn, tmpf); - - sys = system(cmd); - if (sys != 0) - error("imread: error running ImageMagick's 'convert'"); - unlink(tmpf); - endif - - try - fid = fopen(tmpf, "rb"); - catch - unlink(tmpf); - error("imread: could not open temporary file %s", tmpf) - end_try_catch - - fgetl(fid); # P5 or P6 (pgm or ppm) - [width, height] = sscanf(fgetl(fid), "%d %d", "C"); - fgetl(fid); # ignore max components - - if (depth == 16) - ## PGM format has MSB first, i.e. big endian - [data, count] = fread(fid, "uint16", 0, "ieee-be"); - else - [data, count] = fread(fid, "uint8"); - endif - - fclose(fid); - unlink(tmpf); - - if (imtype == "TrueColor") - channels = 3; - else - channels = 1; - endif - if (count != width*height*channels) - error("imread: image data chunk has invalid size") - endif - - varargout = {}; - switch (imtype) - case ("Bilevel") - varargout{1} = logical(reshape(data, width, height)'); - case ("Grayscale") - varargout{1} = uint8(reshape(data, width, height)'); - case ("TrueColor") - varargout{1} = cat(3, reshape(data(1:3:end), width, height)', - reshape(data(2:3:end), width, height)', - reshape(data(3:3:end), width, height)'); - eval(sprintf("varargout{1} = uint%d(varargout{1});", depth)); - - endswitch -endfunction - -function value = re_grab(re, str) - T = regexp(str,re,'tokens'); - if (isempty(T)) - value = ""; - else - value = T{1}{1}; - endif -endfunction
deleted file mode 100644 --- a/imresize.m +++ /dev/null @@ -1,104 +0,0 @@ -## Copyright (C) 2005 Søren Hauberg -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{B}= imresize (@var{A}, @var{m}) -## Scales the image @var{A} by a factor @var{m} using nearest neighbour -## interpolation. If @var{m} is less than 1 the image size will be reduced, -## and if @var{m} is greater than 1 the image will be enlarged. If the image -## is being enlarged the it will be convolved with a 11x11 Gaussian FIR filter -## to reduce aliasing. See below on how to alter this behavior. -## -## @deftypefnx {Function File} @var{B}= imresize (@var{A}, @var{m}, @var{method}) -## Same as above except @var{method} interpolation is performed instead of -## using nearest neighbour. @var{method} can be any method supported by interp2. -## -## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}]) -## Scales the image @var{A} to be of size @var{mrow}x@var{mcol} using nearest -## neighbour interpolation. If the image is being enlarged it will be convolved -## with a lowpass FIR filter as described above. -## -## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}], @var{method}) -## Same as above except @var{method} interpolation is performed instead of using -## nearest neighbour. @var{method} can be any method supported by interp2. -## -## @deftypefnx {Function File} @var{B}= imresize (..., @var{method}, @var{fsize}) -## If the image the image is being enlarged it will usually be convolved with -## a 11x11 Gaussian FIR filter. By setting @var{fsize} to 0 this will be turned -## off, and if @var{fsize} > 0 the image will be convolved with a @var{fsize} -## by @var{fsize} Gaussian FIR filter. -## -## @deftypefnx {Function File} @var{B}= imresize (..., @var{method}, @var{filter}) -## If the image size is being reduced and the @var{filter} argument is passed to -## imresize the image will be convolved with @var{filter} before the resizing -## takes place. -## -## @seealso{interp2} -## @end deftypefn - -## Author: Søren Hauberg <hauberg at gmail dot com> -## -## 2005-04-14 Søren Hauberg <hauberg at gmail dot com> -## * Initial revision - -function [ ret ] = imresize (im, m, method, filter) - if (!isgray(im)) - error("The first argument has to be a gray-scale image."); - endif - [row col] = size(im); - - # Handle the argument that describes the size of the result - if (length(m) == 1) - new_row = round(row*m); - new_col = round(col*m); - elseif (length(m) == 2) - new_row = m(1); - new_col = m(2); - m = min( new_row/row, new_col/col ); - else - error("Bad second argument"); - end - - # Handle the method argument - if (nargin < 3) - method = "nearest"; - endif - - # Handle the filterargument - if (!strcmp(method, "nearest")) - if (nargin < 4) - filter = 11; - endif - if (m > 1 & filter > 0) - # If the image is being enlarged and filter > 0 then - # convolve the image with a filter*filter gaussian. - mu = round(filter/2); - sigma = mu/3; - x = 1:filter; - gauss = 1/sqrt(2*pi*sigma^2) * exp( (-(x-mu).^2)/(2*sigma^2) ); - im = conv2(gauss, gauss, im, "same"); - elseif (m < 1 & nargin == 4) - # If the image size is being reduced and a fourth argument - # is given, use it as a FIR filter. - im = conv2(im, filter, "same"); - endif - endif - - # Perform the actual resizing - [XI YI] = meshgrid( linspace(1,col,new_col), linspace(1,row,new_row) ); - ret = interp2(im, XI, YI, method); - -endfunction
deleted file mode 100644 --- a/imrotate.m +++ /dev/null @@ -1,349 +0,0 @@ -## Copyright (C) 2004-2005 Justus H. Piater -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} -## imrotate(@var{imgPre}, @var{theta}, @var{method}, @var{bbox}) -## Rotation of a 2D matrix about its center. -## -## Input parameters: -## -## @var{imgPre} a gray-level image matrix -## -## @var{theta} the rotation angle in degrees counterclockwise -## -## @var{method} -## @itemize @w -## @item "nearest" neighbor: fast, but produces aliasing effects (default). -## @item "bilinear" interpolation: does anti-aliasing, but is slightly slower. -## @item "bicubic" interpolation: does anti-aliasing, preserves edges better than bilinear interpolation, but gray levels may slightly overshoot at sharp edges. This is probably the best method for most purposes, but also the slowest. -## @item "Fourier" uses Fourier interpolation, decomposing the rotation matrix into 3 shears. This method often results in different artifacts than homography-based methods. Instead of slightly blurry edges, this method can result in ringing artifacts (little waves near high-contrast edges). However, Fourier interpolation is better at maintaining the image information, so that unrotating will result in an image closer to the original than the other methods. -## @end itemize -## -## @var{bbox} -## @itemize @w -## @item "loose" grows the image to accommodate the rotated image (default). -## @item "crop" rotates the image about its center, clipping any part of the image that is moved outside its boundaries. -## @end itemize -## -## Output parameters: -## -## @var{imgPost} the rotated image matrix -## -## @var{H} the homography mapping original to rotated pixel -## coordinates. To map a coordinate vector c = [x;y] to its -## rotated location, compute round((@var{H} * [c; 1])(1:2)). -## @end deftypefn - -## Author: Justus H. Piater <Justus.Piater@ULg.ac.be> -## Created: 2004-10-18 -## Version: 0.7 - -function [imgPost, H] = imrotate(imgPre, thetaDeg, method, bbox) - if (nargin < 4) - bbox = "loose"; - if (nargin < 3) - method = "nearest"; - if (nargin < 2) - usage("imrotate(img, angle [, method [, bbox]]"); - endif - endif - endif - - thetaDeg = mod(thetaDeg, 360); # some code below relies on positive angles - theta = thetaDeg * pi/180; - - sizePre = size(imgPre); - - ## We think in x,y coordinates here (rather than row,column), except - ## for size... variables that follow the usual size() convention. The - ## coordinate system is aligned with the pixel centers. - - R = [cos(theta) sin(theta); -sin(theta) cos(theta)]; - - if (nargin >= 4 && strcmp(bbox, "crop")) - sizePost = sizePre; - else - ## Compute new size by projecting zero-base image corner pixel - ## coordinates through the rotation: - corners = [0, 0; - (R * [sizePre(2) - 1; 0 ])'; - (R * [sizePre(2) - 1; sizePre(1) - 1])'; - (R * [0 ; sizePre(1) - 1])' ]; - sizePost(2) = round(max(corners(:,1)) - min(corners(:,1))) + 1; - sizePost(1) = round(max(corners(:,2)) - min(corners(:,2))) + 1; - ## This size computation yields perfect results for 0-degree (mod - ## 90) rotations and, together with the computation of the center of - ## rotation below, yields an image whose corresponding region is - ## identical to "crop". However, we may lose a boundary of a - ## fractional pixel for general angles. - endif - - ## Compute the center of rotation and the translational part of the - ## homography: - oPre = ([ sizePre(2); sizePre(1)] + 1) / 2; - oPost = ([sizePost(2); sizePost(1)] + 1) / 2; - T = oPost - R * oPre; # translation part of the homography - - ## And here is the homography mapping old to new coordinates: - H = [[R; 0 0] [T; 1]]; - - ## Treat trivial rotations specially (multiples of 90 degrees): - if (mod(thetaDeg, 90) == 0) - nRot90 = mod(thetaDeg, 360) / 90; - if (mod(thetaDeg, 180) == 0 || sizePre(1) == sizePre(2) || - strcmp(bbox, "loose")) - imgPost = rot90(imgPre, nRot90); - return; - elseif (mod(sizePre(1), 2) == mod(sizePre(2), 2)) - ## Here, bbox is "crop" and the rotation angle is +/- 90 degrees. - ## This works only if the image dimensions are of equal parity. - imgRot = rot90(imgPre, nRot90); - imgPost = zeros(sizePre); - hw = min(sizePre) / 2 - 0.5; - imgPost (round(oPost(2) - hw) : round(oPost(2) + hw), - round(oPost(1) - hw) : round(oPost(1) + hw) ) = ... - imgRot(round(oPost(1) - hw) : round(oPost(1) + hw), - round(oPost(2) - hw) : round(oPost(2) + hw) ); - return; - else - ## Here, bbox is "crop", the rotation angle is +/- 90 degrees, and - ## the image dimensions are of unequal parity. This case cannot - ## correctly be handled by rot90() because the image square to be - ## cropped does not align with the pixels - we must interpolate. A - ## caller who wants to avoid this should ensure that the image - ## dimensions are of equal parity. - endif - end - - ## For better readability of this spaghetti implementation, I keep the - ## branches pertaining to the various 'method's all at the first - ## level, even though this causes a slight redundancy in the if - ## statements. - - imgPost = []; - - if (strcmp(method, "Fourier")) - imgPost = imrotate_Fourier(imgPre, thetaDeg, method, bbox); - else - ## This section pertains to all non-Fourier methods. - - ## "Pre" variables hold pre -rotation values; - ## "Post" variables hold post-rotation values. - - ## General rotation: map pixel coordinates back from the Post to the - ## Pre img - Hinv = inv(H); - - ## Target coordinates: - [xPost, yPost] = meshgrid(1:(sizePost(2)), 1:(sizePost(1))); - - ## Compute corresponding source coordinates: - xPre = Hinv(1,1) * xPost + Hinv(1,2) * yPost + Hinv(1,3); - yPre = Hinv(2,1) * xPost + Hinv(2,2) * yPost + Hinv(2,3); - ## zPre is guaranteed to be 1, since the last row of H (and thus of - ## Hinv) is [0 0 1]. - endif - - ## Now map the image using the coordinates computed in the else branch above: - if (strcmp(method, "nearest")) - ## nearest-neighbor: simply round Pre coordinates - xPre = round(xPre); - yPre = round(yPre); - valid = find(1 <= xPre & xPre <= sizePre(2) & - 1 <= yPre & yPre <= sizePre(1) ); - if (!length(valid)) - warning("input image too small"); - imgPost = 0; - return; - endif - - iPre = sub2ind(sizePre , yPre (valid), xPre (valid)); - iPost = sub2ind(sizePost, yPost(valid), xPost(valid)); - - imgPost = zeros(sizePost); - imgPost(iPost) = imgPre(iPre); - elseif(!strcmp(method, "Fourier")) - ## This section pertains to "bilinear" and "bicubic" methods. - - ## With interpolation, one unavoidably loses up to one or two pixel - ## rows or columns at the image boundaries. - - xPreFloor = floor(xPre); - xPreCeil = ceil (xPre); - yPreFloor = floor(yPre); - yPreCeil = ceil (yPre); - - valid = find(1 <= xPreFloor & xPreCeil <= sizePre(2) & - 1 <= yPreFloor & yPreCeil <= sizePre(1) ); - if (!length(valid)) - warning("input image too small"); - imgPost = 0; - return; - endif - - xPreFloor = xPreFloor(valid); - xPreCeil = xPreCeil (valid); - yPreFloor = yPreFloor(valid); - yPreCeil = yPreCeil (valid); - - ## In the following, FC = floor(x), ceil(y), etc. - iPreFF = sub2ind(sizePre, yPreFloor, xPreFloor); - iPreCF = sub2ind(sizePre, yPreFloor, xPreCeil ); - iPreCC = sub2ind(sizePre, yPreCeil , xPreCeil ); - iPreFC = sub2ind(sizePre, yPreCeil , xPreFloor); - - ## We'll have to weight by the fractional part of the coordinates: - xPreFrac = xPre(valid) - xPreFloor; - yPreFrac = yPre(valid) - yPreFloor; - - iPost = sub2ind(sizePost, yPost(valid), xPost(valid)); - endif - - if (strcmp(method, "bilinear")) - imgPost = zeros(sizePost); - ## bilinear interpolation between the four floor and ceiling coordinates - imgPost(iPost) = (imgPre(iPreFF) .* (1 - xPreFrac) .* (1 - yPreFrac) + - imgPre(iPreCF) .* xPreFrac .* (1 - yPreFrac) + - imgPre(iPreCC) .* xPreFrac .* yPreFrac + - imgPre(iPreFC) .* (1 - xPreFrac) .* yPreFrac ); - elseif (strcmp(method, "bicubic")) - ## bicubic interpolation (see Numerical Recipes) - ## This code, together with the prerequisites above, is not limited - ## to this particular use but applies to generic bicubic - ## interpolation in the following scenario: - ## - source data are stored in a matrix, - ## - interpolated coordinates may lie anywhere, no regularity is assumed. - - ## precompute the required derivatives at the source image pixels: - imgPreDx = conv2(imgPre , [ 0.5 0 -0.5] , "same"); - imgPreDy = conv2(imgPre , [-0.5 0 0.5]', "same"); - imgPreDxy = conv2(imgPreDx, [-0.5 0 0.5]', "same"); - - ## Interpolation is done on a square of pixels and their - ## derivatives along x, y, and xy. The square is indexed as: - ## 43 FF CF - ## 12 which corresponds to FC CC - - ## Coefficient matrix W - ## C11 12 21 31 41 p deriv - W = [1 0 -3 2 0 0 0 0 -3 0 9 -6 2 0 -6 4 ## 1 - 0 0 0 0 0 0 0 0 3 0 -9 6 -2 0 6 -4 ## 2 - 0 0 0 0 0 0 0 0 0 0 9 -6 0 0 -6 4 ## 3 - 0 0 3 -2 0 0 0 0 0 0 -9 6 0 0 6 -4 ## 4 - - 0 0 0 0 1 0 -3 2 -2 0 6 -4 1 0 -3 2 ## 1 x - 0 0 0 0 0 0 0 0 -1 0 3 -2 1 0 -3 2 ## 2 x - 0 0 0 0 0 0 0 0 0 0 -3 2 0 0 3 -2 ## 3 x - 0 0 0 0 0 0 3 -2 0 0 -6 4 0 0 3 -2 ## 4 x - - 0 1 -2 1 0 0 0 0 0 -3 6 -3 0 2 -4 2 ## 1 y - 0 0 0 0 0 0 0 0 0 3 -6 3 0 -2 4 -2 ## 2 y - 0 0 0 0 0 0 0 0 0 0 -3 3 0 0 2 -2 ## 3 y - 0 0 -1 1 0 0 0 0 0 0 3 -3 0 0 -2 2 ## 4 y - - 0 0 0 0 0 1 -2 1 0 -2 4 -2 0 1 -2 1 ## 1 xy - 0 0 0 0 0 0 0 0 0 -1 2 -1 0 1 -2 1 ## 2 xy - 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 -1 1 ## 3 xy - 0 0 0 0 0 0 -1 1 0 0 2 -2 0 0 -1 1]; ## 4 xy - - u = 1 - yPreFrac; - values = zeros(size(valid)); - for ci = 4:-1:1 - ## compute ci'th row of matrix C: - - col = 4*(ci - 1) + 1; - c{1} = (W( 1,col) * imgPre (iPreFC) + W( 2,col) * imgPre (iPreCC) + - W( 5,col) * imgPreDx (iPreFC) + W( 6,col) * imgPreDx (iPreCC) ); - - col++; - c{2} = (W( 9,col) * imgPreDy (iPreFC) + W(10,col) * imgPreDy (iPreCC) + - W(13,col) * imgPreDxy(iPreFC) + W(14,col) * imgPreDxy(iPreCC) ); - - for cii = 3:4 - col++; - c{cii} = ... - (W( 1,col) * imgPre (iPreFC) + W( 2,col) * imgPre (iPreCC) + - W( 3,col) * imgPre (iPreCF) + W( 4,col) * imgPre (iPreFF) + - W( 5,col) * imgPreDx (iPreFC) + W( 6,col) * imgPreDx (iPreCC) + - W( 7,col) * imgPreDx (iPreCF) + W( 8,col) * imgPreDx (iPreFF) + - W( 9,col) * imgPreDy (iPreFC) + W(10,col) * imgPreDy (iPreCC) + - W(11,col) * imgPreDy (iPreCF) + W(12,col) * imgPreDy (iPreFF) + - W(13,col) * imgPreDxy(iPreFC) + W(14,col) * imgPreDxy(iPreCC) + - W(15,col) * imgPreDxy(iPreCF) + W(16,col) * imgPreDxy(iPreFF) ); - endfor - - values .*= xPreFrac; - values += ((c{4} .* u + c{3}) .* u + c{2}) .* u + c{1}; - endfor - imgPost = zeros(sizePost); - imgPost(iPost) = values; - endif - - if (!prod(size(imgPost))) - error(sprintf("Interpolation method %s not implemented", method)); - endif -endfunction - -%!test -%! ## Verify minimal loss across six rotations that add up to 360 +/- 1 deg.: -%! methods = { "nearest", "bilinear", "bicubic", "Fourier" }; -%! angles = [ 59 60 61 ]; -%! tolerances = [ 7.4 8.5 8.6 # nearest -%! 3.5 3.1 3.5 # bilinear -%! 2.7 0.1 2.7 # bicubic -%! 2.7 1.6 2.8 ]; # Fourier -%! x = peaks(50); -%! x -= min(min(x)); # Fourier does not handle neg. values well -%! for m = 1:(length(methods)) -%! y = x; -%! for i = 1:5 -%! y = imrotate(y, 60, methods(m), "crop"); -%! end -%! for a = 1:(length(angles)) -%! assert(norm((x - imrotate(y, angles(a), methods(m), "crop")) -%! (10:40, 10:40)) < tolerances(m,a)); -%! end -%! end - - -%!test -%! ## Verify exactness of near-90 and 90-degree rotations: -%! X = rand(99); -%! for angle = [90 180 270] -%! for da = [-0.1 0.1] -%! Y = imrotate(X, angle + da , "nearest"); -%! Z = imrotate(Y, -(angle + da), "nearest"); -%! assert(norm(X - Z) == 0); # exact zero-sum rotation -%! assert(norm(Y - imrotate(X, angle, "nearest")) == 0); # near zero-sum -%! end -%! end - - -%!test -%! ## Verify preserved pixel density: -%! methods = { "nearest", "bilinear", "bicubic", "Fourier" }; -%! ## This test does not seem to do justice to the Fourier method...: -%! tolerances = [ 4 2.2 2.0 209 ]; -%! range = 3:9:100; -%! for m = 1:(length(methods)) -%! t = []; -%! for n = range -%! t(end + 1) = sum(imrotate(eye(n), 20, methods(m))(:)); -%! end -%! assert(t, range, tolerances(m)); -%! end -
deleted file mode 100644 --- a/imrotate_Fourier.m +++ /dev/null @@ -1,170 +0,0 @@ -## Copyright (C) 2002 Jeff Orchard <jorchard@cs.uwaterloo.ca> -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} imrotate(@var{M}, @var{theta}, @var{method}, @var{bbox}) -## Rotation of a 2D matrix. -## -## Applies a rotation of @var{THETA} degrees to matrix @var{M}. -## -## The @var{method} argument is not implemented, and is only included for compatibility with Matlab. -## This function uses Fourier interpolation, -## decomposing the rotation matrix into 3 shears. -## -## @var{bbox} can be either 'loose' or 'crop'. -## 'loose' allows the image to grow to accomodate the rotated image. -## 'crop' keeps the same size as the original, clipping any part of the image -## that is moved outside the bounding box. -## @end deftypefn - -## Author: Jeff Orchard <jorchard@cs.uwaterloo.ca> -## Created: Oct. 14, 2002 - -function fs = imrotate_Fourier(f,theta,method,bbox) - - if ( nargin == 2 ) - method = "fourier"; - bbox = "loose"; - elseif ( nargin == 3 ) - bbox = "loose"; - endif - - # Get original dimensions. - [ydim_orig, xdim_orig] = size(f); - - # This finds the index coords of the centre of the image (indices are base-1) - # eg. if xdim_orig=8, then xcentre_orig=4.5 (half-way between 1 and 8) - xcentre_orig = (xdim_orig+1) / 2; - ycentre_orig = (ydim_orig+1) / 2; - - # Pre-process the angle =========================================================== - # Whichever 90 degree multiple theta is closest to, that multiple of 90 will - # be implemented by rot90. The remainder will be done by shears. - - # This ensures that 0 <= theta < 360. - theta = rem( rem(theta,360) + 360, 360 ); - - # This is a flag to keep track of 90-degree rotations. - perp = 0; - - if ( theta>=0 && theta<=45 ) - phi = theta; - elseif ( theta>45 && theta<=135 ) - phi = theta - 90; - f = rot90(f,1); - perp = 1; - elseif ( theta>135 && theta<=225 ) - phi = theta - 180; - f = rot90(f,2); - elseif ( theta>225 && theta<=315 ) - phi = theta - 270; - f = rot90(f,3); - perp = 1; - else - phi = theta; - endif - - - - if ( phi == 0 ) - fs = f; - if ( strcmp(bbox,"loose") == 1 ) - return; - else - xmax = xcentre_orig; - ymax = ycentre_orig; - if ( perp == 1 ) - xmax = max([xmax ycentre_orig]); - ymax = max([ymax xcentre_orig]); - [ydim xdim] = size(fs); - xpad = ceil( xmax - (xdim+1)/2 ); - ypad = ceil( ymax - (ydim+1)/2 ); - fs = impad(fs, [xpad,xpad], [ypad,ypad], "zeros"); - endif - xcentre_new = (size(fs,2)+1) / 2; - ycentre_new = (size(fs,1)+1) / 2; - endif - else - - # At this point, we can assume -45<theta<45 (degrees) - - phi = phi * pi / 180; - theta = theta * pi / 180; - R = [ cos(theta) -sin(theta) ; sin(theta) cos(theta) ]; - - # Find max of each dimension... this will be expanded for "loose" and "crop" - xmax = xcentre_orig; - ymax = ycentre_orig; - - # If we don't want wrapping, we have to zeropad. - # Cropping will be done later, if necessary. - if ( strcmp(bbox, "wrap") == 0 ) - corners = ( [ xdim_orig xdim_orig -xdim_orig -xdim_orig ; ydim_orig -ydim_orig ydim_orig -ydim_orig ] + 1 )/ 2; - rot_corners = R * corners; - xmax = max([xmax rot_corners(1,:)]); - ymax = max([ymax rot_corners(2,:)]); - - # If we are doing a 90-degree rotation first, we need to make sure our - # image is large enough to hold the rot90 image as well. - if ( perp == 1 ) - xmax = max([xmax ycentre_orig]); - ymax = max([ymax xcentre_orig]); - endif - - [ydim xdim] = size(f); - xpad = ceil( xmax - xdim/2 ); - ypad = ceil( ymax - ydim/2 ); - %f = impad(f, [xpad,xpad], [ypad,ypad], "zeros"); - xcentre_new = (size(f,2)+1) / 2; - ycentre_new = (size(f,1)+1) / 2; - endif - - #size(f) - [S1 S2] = MakeShears(phi); - - tic; - f1 = imshear(f, 'x', S1(1,2), 'loose'); - f2 = imshear(f1, 'y', S2(2,1), 'loose'); - fs = real( imshear(f2, 'x', S1(1,2), 'loose') ); - %fs = f2; - xcentre_new = (size(fs,2)+1) / 2; - ycentre_new = (size(fs,1)+1) / 2; - endif - - if ( strcmp(bbox, "crop") == 1 ) - - # Translate the current centre to centre_orig - fs = imtranslate(fs, xcentre_orig-xcentre_new, -ycentre_orig+ycentre_new, "wrap"); - - # Crop to original dimensions - fs = fs(1:ydim_orig, 1:xdim_orig); - - elseif ( strcmp(bbox, "loose") == 1 ) - - # Find tight bounds on size of rotated image - # These should all be positive, or 0. - xmax_loose = ceil( xcentre_new + max(rot_corners(1,:)) ); - xmin_loose = floor( xcentre_new - max(rot_corners(1,:)) ); - ymax_loose = ceil( ycentre_new + max(rot_corners(2,:)) ); - ymin_loose = floor( ycentre_new - max(rot_corners(2,:)) ); - - %fs = fs( (ymin_loose+1):(ymax_loose-1) , (xmin_loose+1):(xmax_loose-1) ); - fs = fs( (ymin_loose+1):(ymax_loose-1) , (xmin_loose+1):(xmax_loose-1) ); - - endif - - -endfunction
deleted file mode 100644 --- a/imshear.m +++ /dev/null @@ -1,131 +0,0 @@ -## Copyright (C) 2002 Jeff Orchard -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} -## imshear (@var{M}, @var{axis}, @var{alpha}, @var{bbox}) -## Applies a shear to @var{M}. -## -## The argument @var{M} is either a matrix or an RGB image. -## -## @var{axis} is the axis along which the shear is to be applied, and can -## be either 'x' or 'y'. -## For example, to shear sideways is to shear along the 'x' axis. Choosing -## 'y' causes an up/down shearing. -## -## @var{alpha} is the slope of the shear. For an 'x' shear, it is the -## horizontal shift (in pixels) applied to the pixel above the -## center. For a 'y' shear, it is the vertical shift (in pixels) -## applied to the pixel just to the right of the center pixel. -## -## NOTE: @var{alpha} does NOT need to be an integer. -## -## @var{bbox} can be one of 'loose', 'crop' or 'wrap'. -## 'loose' allows the image to grow to accomodate the new transformed image. -## 'crop' keeps the same size as the original, clipping any part of the image -## that is moved outside the bounding box. -## 'wrap' keeps the same size as the original, but does not clip the part -## of the image that is outside the bounding box. Instead, it wraps it back -## into the image. -## -## If called with only 3 arguments, @var{bbox} is set to 'loose' by default. -## @end deftypefn - -## Author: Jeff Orchard <jjo@sfu.ca> -## Created: June 2002 - -function g = imshear(m, axis, alpha, bbox, noshift) - - # The code below only does y-shearing. This is because of - # the implementation of fft (operates on columns, but not rows). - # So, transpose first for x-shearing. - if ( strcmp(axis, "x")==1 ) - m = m'; - endif - - if ( nargin < 4 ) - bbox = "loose"; - noshift = 0; - elseif ( nargin < 5 ) - noshift = 0; - endif - - [ydim_orig xdim_orig] = size(m); - if ( strcmp(bbox, "wrap") == 0 ) - ypad = ceil( (xdim_orig+1)/2 * abs(alpha) ); - m = impad(m, [0,0], [ypad,ypad]); - endif - - [ydim_new xdim_new] = size(m); - xcentre = ( xdim_new + 1 ) / 2; - ycentre = ( ydim_new + 1 ) / 2; - - # This applies FFT to columns of m (x-axis remains a spatial axis). - # Because the way that fft and fftshift are implemented, the origin - # will move by 1/2 pixel, depending on the polarity of the image - # dimensions. - # - # If dim is even (=2n), then the origin of the fft below is located - # at the centre of pixel (n+1). ie. if dim=16, then centre is at 9. - # - # If dim is odd (=2n+1), then the origin of the fft below is located - # at the centre of pixel (n). ie. if dim=15, then centre is at 8. - if ( noshift==1 ) - M = fft(m); - else - #M = imtranslate(fft(imtranslate(m, -xcentre, ycentre, "wrap")), xcentre, -ycentre, "wrap"); - M = fftshift(fft(fftshift(m))); - endif - - [ydim xdim] = size(m); - x = zeros(ydim, xdim); - - # Find coords of the origin of the image. - if ( noshift==1 ) - xc_coord = 1; - yc_coord = 1; - l = (1:ydim)' - yc_coord; - r = (1:xdim) - xc_coord; - if ( strcmp(bbox, "wrap")==1 ) - l((ydim/2):ydim) = l((ydim/2):ydim) - ydim; - r((xdim/2):xdim) = r((xdim/2):xdim) - xdim; - endif - else - xc_coord = (xdim+1)/2; - yc_coord = (ydim+1)/2; - l = (1:ydim)' - yc_coord; - r = (1:xdim) - xc_coord; - endif - x = l * r; - - Ms = M.* exp(2*pi*I*alpha/ydim * x); - - if ( noshift==1 ) - g = abs(ifft(Ms)); - else - #g = abs(imtranslate( ifft( imtranslate(Ms, -xcentre, ycentre, "wrap") ), xcentre, -ycentre, "wrap")); - g = abs( fftshift(ifft(ifftshift(Ms))) ); - endif - - if ( strcmp(bbox, "crop")==1 ) - g = g(ypad+1:ydim_orig+ypad, :); - endif - - # Un-transpose if x-shearing was wanted - if ( strcmp(axis, "x")==1 ) - g = g'; - endif -endfunction
deleted file mode 100644 --- a/imtranslate.m +++ /dev/null @@ -1,70 +0,0 @@ -## Copyright (C) 2002 Jeff Orchard -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{Y}} = -## imtranslate (@var{M}, @var{x}, @var{y} [, @var{bbox}]) -## Translate a 2D image by (x,y) using Fourier interpolation. -## -## @var{M} is a matrix, and is translated to the right by @var{X} pixels -## and translated up by @var{Y} pixels. -## -## @var{bbox} can be either 'crop' or 'wrap' (default). -## -## @end deftypefn - -## Author: Jeff Orchard <jjo@cs.sfu.ca> - -function Y = imtranslate(X, a, b, bbox_in) - - bbox = "wrap"; - if ( nargin > 3 ) - bbox = bbox_in; - endif - - if ( strcmp(bbox, "crop")==1 ) - - xpad = [0,0]; - if (a>0) - xpad = [0,ceil(a)]; - elseif (a<0) - xpad = [-ceil(a),0]; - endif - - ypad = [0,0]; - if (b>0) - ypad = [ceil(b),0]; - elseif (b<0) - ypad = [0,-ceil(b)]; - endif - - X = impad(X, xpad, ypad, 'zeros'); - endif - - - [dimy, dimx] = size(X); - x = ifftshift(fft2(fftshift(X))); - px = exp(-2*pi*i*a*(0:dimx-1)/dimx); - py = exp(-2*pi*i*b*(0:dimy-1)/dimy)'; - P = py * px; - y = x .* P; - Y = abs( ifftshift(ifft2(fftshift(y))) ); - #Y = ifftshift(ifft2(fftshift(y))); - - if ( strcmp(bbox, "crop")==1 ) - Y = Y( ypad(1)+1:dimy-ypad(2) , xpad(1)+1:dimx-xpad(2)); - endif -endfunction
deleted file mode 100644 --- a/imwrite.m +++ /dev/null @@ -1,273 +0,0 @@ -## Copyright (C) 2002 Andy Adler -## -## This program is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2, or (at your option) -## any later version. USE THIS SOFTWARE AT YOUR OWN RISK. - -#IMWRITE: write image from octave to various file formats -# -# Note: this requires the ImageMagick "convert" utility. -# get this from www.imagemagick.org if required -# additional documentation of options is available from the -# convert man page -# -# BASIC USAGE: -# imwrite( fname, img ) -# - img is a greyscale (0-255) of image in fname -# imwrite( fname, img, map ) -# - map is a matrix of [r,g,b], 0-1 triples -# - img is a matrix on indeces into map -# imwrite( fname, r,g,b ); -# - r,g,b are red,green,blue (0-255) compondents -# -# Formats for image fname -# 1. simple guess from extention ie "fig.jpg", "blah.gif" -# 2. specify explicitly "jpg:fig.jpg", "gif:blah.gif" -# 3. specify subimage for multi-image format "tiff:file.tif[3]" -# 4. raw images (row major format) specify geometry -# "raw:img[256x180]" -# -# IMREAD OPTIONS: -# imread will support most of the options for convert.1 -# -# imwrite( fname, img, options ) -# imwrite( fname, img, map, options ) -# imwrite( fname, r,g,b, options ); -# -# where options is a string matrix (or list) of options -# -# example: options= ["-rotate 25"; -# "-crop 200x200+150+150"; -# "-sample 200%" ]; -# will rotate, crop, and then expand the image. -# note that the order of operations is important -# -# The following options are supported -# -antialias remove pixel-aliasing -# -background color background color -# -blur geometry blur the image -# -border geometry surround image with a border of color -# -bordercolor color border color -# -box color color for annotation bounding box -# -charcoal radius simulate a charcoal drawing -# -colorize value colorize the image with the fill color -# -colors value preferred number of colors in the image -# -colorspace type alternate image colorspace -# -comment string annotate image with comment -# -compress type type of image compression -# -contrast enhance or reduce the image contrast -# -crop geometry preferred size and location of the cropped image -# -density geometry vertical and horizontal density of the image -# -depth value depth of the image -# -despeckle reduce the speckles within an image -# -dispose method GIF disposal method -# -dither apply Floyd/Steinberg error diffusion to image -# -draw string annotate the image with a graphic primitive -# -edge radius apply a filter to detect edges in the image -# -emboss radius emboss an image -# -enhance apply a digital filter to enhance a noisy image -# -equalize perform histogram equalization to an image -# -fill color color to use when filling a graphic primitive -# -filter type use this filter when resizing an image -# -flip flip image in the vertical direction -# -flop flop image in the horizontal direction -# -font name font for rendering text -# -frame geometry surround image with an ornamental border -# -fuzz distance colors within this distance are considered equal -# -gamma value level of gamma correction -# -geometry geometry perferred size or location of the image -# -gaussian geometry gaussian blur an image -# -gravity type vertical and horizontal text placement -# -implode amount implode image pixels about the center -# -intent type Absolute, Perceptual, Relative, or Saturation -# -interlace type None, Line, Plane, or Partition -# -label name assign a label to an image -# -level value adjust the level of image contrast -# -list type Color, Delegate, Format, Magic, Module, or Type -# -map filename transform image colors to match this set of colors -# -matte store matte channel if the image has one -# -median radius apply a median filter to the image -# -modulate value vary the brightness, saturation, and hue -# -monochrome transform image to black and white -# -morph value morph an image sequence -# -negate replace every pixel with its complementary color -# -noise radius add or reduce noise in an image -# -normalize transform image to span the full range of colors -# -opaque color change this color to the fill color -# -page geometry size and location of an image canvas -# -paint radius simulate an oil painting -# -profile filename add ICM or IPTC information profile to image -# -quality value JPEG/MIFF/PNG compression level -# -raise value lighten/darken image edges to create a 3-D effect -# -region geometry apply options to a portion of the image -# -roll geometry roll an image vertically or horizontally -# -rotate degrees apply Paeth rotation to the image -# -sample geometry scale image with pixel sampling -# -scale geometry resize image -# -segment values segment an image -# -seed value pseudo-random number generator seed value -# -shade degrees shade the image using a distant light source -# -sharpen geometry sharpen the image -# -shave geometry shave pixels from the image edges -# -shear geometry slide one edge of the image along the X or Y axis -# -size geometry width and height of image -# -solarize threshold negate all pixels above the threshold level -# -spread amount displace image pixels by a random amount -# -stroke color color to use when stoking a graphic primitive -# -strokewidth value width of stroke -# -swirl degrees swirl image pixels about the center -# -texture filename name of texture to tile onto the image background -# -threshold value threshold the image -# -tile filename tile image when filling a graphic primitive -# -transparent color make this color transparent within the image -# -treedepth value depth of the color tree -# -type type image type -# -units type PixelsPerInch, PixelsPerCentimeter, or Undefined -# -unsharp geometry sharpen the image - -function imwrite(fname, p2, p3 ,p4 ,p5 ); - -try save_empty_list_elements_ok= empty_list_elements_ok; -catch save_empty_list_elements_ok= 0; -end -try save_warn_empty_list_elements= warn_empty_list_elements; -catch save_warn_empty_list_elements= 0; -end -unwind_protect -empty_list_elements_ok= 1; -warn_empty_list_elements= 0; - -# some older versions of octave didn't seem handle piped output correctly -usepipe=1; - -if ( nargin <= 1 ) || ... - ( ! ischar (fname)) || ... - ( nargin == 2 && ischar(p2) ) - usage([ ... - "imwrite( fname, img )\n", ... - "imwrite( fname, img, map )\n", ... - "imwrite( fname, r,g,b );\n", ... - "imwrite( fname, img, options )\n", ... - "imwrite( fname, img, map, options )\n", ... - "imwrite( fname, r,g,b, options );\n"]); -endif - -# Put together the options string -# TODO: add some error checking to options -option_str=""; -n_mat= nargin-1; - -options= eval(sprintf("p%d",nargin)); -# process options strings if given -if ischar(options) - n_mat--; - for i= 1:size(options,1) - option_str=[option_str," ", options(i,:) ]; - end -elseif is_list( options ) - n_mat--; - for i= 1:length(options) - option_str=[option_str," ", nth(options,i) ]; - end -end - -[hig,wid] = size(p2); -if n_mat==1 - data= p2'; - outputtype="pgm"; - pnm_sig="P5"; -elseif n_mat==2 - img= p2'; - data= [ 255*reshape(p3(img,1),1, hig*wid); - 255*reshape(p3(img,2),1, hig*wid); - 255*reshape(p3(img,3),1, hig*wid) ]; - outputtype="ppm"; - pnm_sig="P6"; -elseif n_mat==3 - data= [ reshape(p2',1, hig*wid); - reshape(p3',1, hig*wid); - reshape(p4',1, hig*wid) ]; - outputtype="ppm"; - pnm_sig="P6"; -else - error("imwrite: too many data matrices specified"); -end - -if usepipe - pname= sprintf("convert %s %s:- '%s' 2>/dev/null", - option_str, outputtype, fname); - fid= popen(pname ,'w'); - - if fid<0; - error('could not create image data. Is ImageMagick installed?'); - end -else - tnam= tmpnam(); - cmd= sprintf("convert %s '%s:%s' '%s' 2>/dev/null", - option_str, outputtype, tnam, fname); - fid= fopen(tnam, "wb"); -end - - fprintf(fid,"%s\n%d %d\n255\n",pnm_sig,wid,hig); - write_count= fwrite(fid,data(:)); - if write_count != prod(size(data)) - fclose(fid); - if ~usepipe - unlink(tnam); - end - error(['Problem writing image: ', fname ]); - end - - fclose(fid); - if ~usepipe - retcode = system(cmd); - if retcode !=0 - error('could not call imagemagick convert'); - end - unlink( tnam ); - end - -unwind_protect_cleanup -empty_list_elements_ok= save_empty_list_elements_ok; -warn_empty_list_elements= save_warn_empty_list_elements; -end_unwind_protect - -# -# $Log$ -# Revision 1.11 2006/03/22 17:50:47 qspencer -# Change calls to 'system' function to reflect new ordering of output arguments. -# -# Revision 1.10 2005/09/08 02:00:17 pkienzle -# [for Bill Denney] isstr -> ischar -# -# Revision 1.9 2005/07/21 16:03:02 aadler -# Improve error messages and use pipes -# -# Revision 1.8 2005/05/25 03:43:40 pkienzle -# Author/Copyright consistency -# -# Revision 1.7 2005/04/25 01:05:28 aadler -# added GPL copyrights -# -# Revision 1.6 2003/09/12 14:22:42 adb014 -# Changes to allow use with latest CVS of octave (do_fortran_indexing, etc) -# -# Revision 1.5 2003/07/25 19:11:41 pkienzle -# Make sure all files names referenced in system calls are wrapped in quotes -# to protect against spaces in the path. -# -# Revision 1.4 2002/11/27 08:40:11 pkienzle -# author/license updates -# -# Revision 1.3 2002/03/19 18:14:13 aadler -# unfortunately using popen seems to create problems, mostly -# on win32, but also on linux, so we need to move to a tmpfile approach -# -# Revision 1.2 2002/03/17 05:26:14 aadler -# now accept filenames with spaces -# -# Revision 1.1 2002/03/11 01:56:47 aadler -# general image read/write functionality using imagemagick utilities -# -#
new file mode 100644 --- /dev/null +++ b/inst/MakeShears.m @@ -0,0 +1,7 @@ +function [S1, S2] = MakeShears(theta) + +S1 = eye(2); +S2 = eye(2); + +S1(1,2) = -tan(theta/2); +S2(2,1) = sin(theta);
new file mode 100644 --- /dev/null +++ b/inst/applylut.m @@ -0,0 +1,62 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{A} = } applylut (@var{BW},@var{LUT}) +## Uses lookup tables to perform a neighbour operation on binary images. +## +## A = applylut(BW,LUT) returns the result of a neighbour operation +## using the lookup table @var{LUT} which can be created by makelut. +## +## It first computes a matrix with the index of each element in the +## lookup table. To do this, it convolves the original matrix with a +## matrix which assigns each of the neighbours a bit in the resulting +## index. Then @var{LUT} is accessed to compute the result. +## +## @end deftypefn +## @seealso{makelut} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function A = applylut(BW, LUT) + if (nargin != 2) + usage ("A = applylut(BW, LUT)"); + endif + + nq=log2(length(LUT)); + n=sqrt(nq); + if (floor(n)!=n) + error ("applylut: LUT length is not as expected. Use makelut to create it."); + endif + w=reshape(2.^[nq-1:-1:0],n,n); + A=LUT(filter2(w,BW)+1); +endfunction + +%!demo +%! lut=makelut(inline('sum(x(:))>=3','x'), 3); +%! applylut(eye(5),lut) +%! % everything should be 0 despite a diagonal which +%! % doesn't reach borders. + + +%!assert(prod(applylut(eye(3),makelut(inline('x(1,1)==1','x'),2))==eye(3))==1); % 2-by-2 test +%!assert(prod(applylut(eye(3),makelut(inline('x(2,2)==1','x'),3))==eye(3))==1); % 3-by-3 test +%!assert(prod(applylut(eye(3),makelut(inline('x(3,3)==1','x'),3))== \ +%! applylut(eye(3),makelut(inline('x(2,2)==1','x'),2)))==1); + + + +
new file mode 100644 --- /dev/null +++ b/inst/autumn.m @@ -0,0 +1,51 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} autumn (@var{n}) +## Create color colormap. +## (red through orange to yellow) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = autumn (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("autumn: argument must be a scalar"); + endif + else + usage ("autumn (number)"); + endif + + if (number == 1) + map = [1, 0, 0]; + elseif (number > 1) + r = ones (number, 1); + g = (0:number - 1)' ./ (number - 1); + b = zeros (number, 1); + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/bestblk.m @@ -0,0 +1,113 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{siz} = } bestblk ([@var{m} @var{n}], @var{k}) +## @deftypefnx {Function File} {[@var{mb} @var{nb}] = } bestblk ([@var{m} @var{n}], @var{k}) +## Calculates the best size of block for block processing. +## +## @code{siz=bestblk([m,n],k)} calculates the optimal block size for block +## processing for a @var{m}-by-@var{n} image. @var{k} is the maximum +## side dimension of the block. Its default value is 100. @var{siz} is a +## row vector which contains row and column dimensions for the block. +## +## @code{[mb,nb]=bestblk([m,n],k)} behaves as described above but +## returns block dimensions to @var{mb} and @var{nb}. +## +## @strong{Algorithm:} +## +## For each dimension (@var{m} and @var{n}), it follows this algorithm: +## +## 1.- If dimension is less or equal than @var{k}, it returns the +## dimension value. +## +## 2.- If not then returns the value between +## @code{round(min(dimension/10,k/2))} which minimizes padding. +## +## +## @end deftypefn +## @seealso{blkproc} + + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function [varargout] = bestblk(ims,k) + if(nargin<1 || nargin>2) + usage("siz=bestblk([m,n],k), [mb,nb]=bestblk([m,n],k)"); + endif + if(nargout>2) + usage("siz=bestblk([m,n],k), [mb,nb]=bestblk([m,n],k)"); + endif + if(nargin<2) + k=100; + endif + if(!isvector(ims)) + error("bestblk: first parameter is not a vector."); + endif + ims=ims(:); + if(length(ims)!=2) + error("bestblk: length of first parameter is not 2."); + endif + + mb=mi=ims(1); + p=mi; + if(mi>k) + for i=round(min(mi/10,k/2)):k + pt=rem(mi,i); + if(pt<p) + p=pt; + mb=i; + endif + endfor + endif + + nb=ni=ims(2); + p=ni; + if(ni>k) + for i=round(min(ni/10,k/2)):k + pt=rem(ni,i); + if(pt<p) + p=pt; + nb=i; + endif + endfor + endif + + if(nargout<=1) + varargout{1}=[mb;nb]; + else + varargout{1}=mb; + varargout{2}=nb; + endif + +endfunction + +%!demo +%! siz=bestblk([200;10],50) +%! # Best block is [20,10] + +%!assert(bestblk([300;100],150),[30;100]); +%!assert(bestblk([256,128],17),[16;16]); + +% $Log$ +% Revision 1.1 2006/08/20 12:59:31 hauberg +% Changed the structure to match the package system +% +% Revision 1.2 2005/07/03 01:10:19 pkienzle +% Try to correct for missing newline at the end of the file +% +% Revision 1.1 2004/08/15 19:01:05 jmones +% bestblk added: Calculates best block size for block processing
new file mode 100644 --- /dev/null +++ b/inst/blkproc.m @@ -0,0 +1,193 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{B} = } blkproc (@var{A}, [@var{m},@var{n}], @var{fun}) +## @deftypefnx {Function File} {@var{B} = } blkproc (@var{A}, [@var{m},@var{n}], @var{fun}, ...) +## @deftypefnx {Function File} {@var{B} = } blkproc (@var{A}, [@var{m},@var{n}], [@var{mborder},@var{nborder}], @var{fun}, @var{...}) +## @deftypefnx {Function File} {@var{B} = } blkproc (@var{A}, 'indexed', ...) +## Processes image in blocks using user-supplied function +## +## @code{B=blkproc(A,[m,n],fun)} divides image @var{A} in +## @var{m}-by-@var{n} blocks, and passes them to user-supplied function +## @var{fun}, which result is concatenated to build returning matrix +## @var{B}. If padding is needed to build @var{m}-by-@var{n}, it is added +## at the bottom and right borders of the image. 0 is used as a padding +## value. +## +## @code{B=blkproc(A,[m,n],fun,...)} behaves as described above but +## passes extra parameters to function @var{fun}. +## +## @code{B=blkproc(A,[m,n],[mborder,nborder],fun,...)} behaves as +## described but uses blocks which overlap with neighbour blocks. +## Overlapping dimensions are @var{mborder} vertically and @var{nborder} +## horizontally. This doesn't change the number of blocks in an image +## (which depends only on size(@var{A}) and [@var{m},@var{n}]). Adding a +## border requires extra padding on all edges of the image. 0 is used as +## a padding value. +## +## @code{B=blkproc(A,'indexed',...)} assumes that @var{A} is an indexed +## image, so it pads the image using proper value: 0 for uint8 and +## uint16 images and 1 for double images. Keep in mind that if 'indexed' +## is not specified padding is always done using 0. +## +## @end deftypefn +## @seealso{colfilt,inline,bestblk} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function B = blkproc(A, varargin) + if(nargin<3) + error("blkproc: invalid number of parameters."); + endif + + ## check 'indexed' presence + indexed=false; + p=1; + if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) + indexed=true; + p+=1; + if(isa(A,"uint8") || isa(A,"uint16")) + padval=0; + else + padval=1; + endif + else + padval=0; + endif + + ## check [m,n] + if(!isvector(varargin{p})) + error("blkproc: expected [m,n] but param is not a vector."); + endif + if(length(varargin{p})!=2) + error("blkproc: expected [m,n] but param has wrong length."); + endif + sblk=varargin{p}(:); + p+=1; + + ## check [mborder,nborder] + if(nargin<p) + error("blkproc: required parameters haven't been supplied."); + endif + + if(isvector(varargin{p})) + if(length(varargin{p})!=2) + error("blkproc: expected [mborder,nborder] but param has wrong length."); + endif + sborder=varargin{p}(:); + p+=1; + else + sborder=[0;0]; + endif + + ## check fun + ## TODO: add proper checks for this one + if(nargin<p) + error("blkproc: required parameters haven't been supplied."); + endif + + fun=varargin{p}; + if(!isa(fun,"function handle") && + !isa(fun,"inline function") && + !ischar(fun)) + error("blkproc: invalid fun parameter."); + endif + + ## remaining params are params to fun + ## extra params are p+1:nargin-1 + + ## First of all we calc needed padding which will be applied on bottom + ## and right borders + ## The "-" makes the function output needed elements to fill another + ## block directly + sp=mod(-size(A)',sblk); + + if(any(sp)) + A=padarray(A,sp,padval,'post'); + endif + + ## we store A size without border padding to iterate later + soa=size(A); + + ## If we have borders then we need more padding + if(any(sborder)) + A=padarray(A,sborder,padval); + endif + + ## calculate end of block + eblk=sblk+sborder*2-1; + + ## now we can process by blocks + ## we try to preserve fun return type by concatenating everything + for i=1:sblk(1):soa(1) + ## This assures r has the same class as returned by fun + r=feval(fun,A(i:i+eblk(1),1:1+eblk(2)),varargin{p+1:nargin-1}); + for j=1+sblk(2):sblk(2):soa(2) + r=horzcat(r,feval(fun,A(i:i+eblk(1),j:j+eblk(2)),varargin{p+1:nargin-1})); + endfor + if(i==1) ## this assures B has the same class as A + B=r; + else + B=vertcat(B,r); + endif + endfor +endfunction + +%!demo +%! blkproc(eye(6),[2,2],inline("any(x(:))","x")) +%! # Returns a 3-by-3 diagonal + + +%!assert(blkproc(eye(6),[2,2],"sum"),blkproc(eye(6),[2,2],@sum)); +%!assert(blkproc(eye(6),[2,2],"sum"),blkproc(eye(6),[2,2],inline("sum(x)","x"))); +%!assert(blkproc(eye(6),[1,2],@sum),kron(eye(3),[1;1])); +%!assert(blkproc(eye(6),[2,2],inline("any(x(:))","x")),eye(3)!=0); +%!assert(blkproc(eye(6),[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); +%!assert(blkproc(eye(6),'indexed',[1,2],[1,1],inline("sum(x(:))","x")),[8,5,6;6,2,3;5,3,4;4,3,5;3,2,6;6,5,8]); +%!assert(blkproc(eye(6),[2,3],[4,3],inline("sum(x(:))","x")),ones(3,2)*6); + +% Some int* and uint* tests +%!assert(blkproc(eye(6),[2,2],inline("int8(sum(x(:)))","x")),eye(3,"int8")*2); + +% Padding is 0 even for indexed +%!assert(blkproc(uint8(eye(6)),[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); +%!assert(blkproc(uint8(eye(6)),'indexed',[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); +%!assert(blkproc(uint16(eye(6)),[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); +%!assert(blkproc(uint16(eye(6)),'indexed',[1,2],[1,1],inline("sum(x(:))","x")),[2,1,0;3,2,0;2,3,1;1,3,2;0,2,3;0,1,2]); + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:31 hauberg +% Changed the structure to match the package system +% +% Revision 1.5 2005/09/08 02:00:17 pkienzle +% [for Bill Denney] isstr -> ischar +% +% Revision 1.4 2004/11/15 16:04:20 pkienzle +% Fix tests for functions which return boolean matrices +% +% Revision 1.3 2004/09/03 17:49:37 jmones +% Improved uint8 and uint16 padding expections +% +% Revision 1.2 2004/09/03 13:40:13 jmones +% Check result has same class as function result, and improved fun param checking +% +% Revision 1.1 2004/08/15 19:27:46 jmones +% blkproc: block process an image using user-supplied function +% +%
new file mode 100644 --- /dev/null +++ b/inst/bmpwrite.m @@ -0,0 +1,88 @@ +## bmpwrite(X,map,file) +## Write the bitmap X into file (8-bit indexed uncompressed). +## The values in X are indices into the given RGB colour map. +## bmpwrite(X,file) +## Write the bitmap X into file (24-bit truecolor uncompressed). +## X is an m x n x 3 array of R,G,B values. + +## This code is in the public domain. +## Author: Paul Kienzle <pkienzle@users.sf.net> + +function bmpwrite(x,map,file) + if nargin==2 + bmpwrite_truecolor(x,map); + else + bmpwrite_indexed(x,map,file); + endif +endfunction + +function bmpwrite_truecolor(x,file) + h = rows(x); w = columns(x); + padw = ceil(3*w/4)*4-3*w; + header = 14+40; + filesize = header+h*(3*w+padw); + arch = "ieee-le"; + file = fopen(file, "wb"); + fwrite(file,toascii("BM"),"uchar",0,arch); # file tag + fwrite(file,filesize,"long",0,arch); # length of file + fwrite(file,0,"long",0,arch); # reserved + fwrite(file,header,"long",0,arch); # offset of raster data in file + + fwrite(file,40,"long",0,arch); # header size + fwrite(file,w,"long",0,arch); # image width + fwrite(file,h,"long",0,arch); # image height + fwrite(file,1,"short",0,arch); # number of planes + fwrite(file,24,"short",0,arch); # pixels per plane + fwrite(file,0,"long",0,arch); # compression (none) + fwrite(file,0,"long",0,arch); # compressed size of image + resolution = 72/2.54*100; # 72 dpi / 2.54 cm/in * 100 cm/m + fwrite(file,resolution,"long",0,arch); # horizontal resolution + fwrite(file,resolution,"long",0,arch); # vertical resolution + fwrite(file,0,"long",0,arch); # number of colours used + fwrite(file,0,"long",0,arch); # number of "important" colors + + ## raster image, lines written bottom to top. + R = x(end:-1:1,:,1)'; + G = x(end:-1:1,:,2)'; + B = x(end:-1:1,:,3)'; + RGB=[B(:),G(:),R(:)]'; # Now [[B;G;R],[B;G;R],...,[B;G;R]] + RGB=reshape(RGB,3*w,h); # Now [[B;G;R;...;B;G;R],...,[B;G;R;...;B;G;R]] + fwrite(file,[RGB;zeros(padw,h)],"uchar",0,arch); + fclose(file); +endfunction + +function bmpwrite_indexed(x,map,file) + [h,w] = size(x); + padw = ceil(w/4)*4-w; + header = 14+40+4*rows(map); + filesize = header+(w+padw)*h; + arch = "ieee-le"; + file = fopen(file, "wb"); + fwrite(file,toascii("BM"),"uchar",0,arch); # file tag + fwrite(file,filesize,"long",0,arch); # length of file + fwrite(file,0,"long",0,arch); # reserved + fwrite(file,header,"long",0,arch); # offset of raster data in file + + fwrite(file,40,"long",0,arch); # header size + fwrite(file,w,"long",0,arch); # image width + fwrite(file,h,"long",0,arch); # image height + fwrite(file,1,"short",0,arch); # number of planes + fwrite(file,8,"short",0,arch); # pixels per plane + fwrite(file,0,"long",0,arch); # compression (none) + fwrite(file,0,"long",0,arch); # compressed size of image + resolution = 72/2.54*100; # 72 dpi / 2.54 cm/in * 100 cm/m + fwrite(file,resolution,"long",0,arch); # horizontal resolution + fwrite(file,resolution,"long",0,arch); # vertical resolution + fwrite(file,rows(map),"long",0,arch); # number of colours used + fwrite(file,0,"long",0,arch); # number of "important" colors + + ## colormap BGR0BGR0BGR0BGR0... + map=[round(map*255), zeros(rows(map),1)]; + map=map(:,[3,2,1,4]); + fwrite(file,map',"uchar",0,arch); + + ## raster image, each line on a 32-bit boundary, padded with zeros + ## lines written bottom to top. + fwrite(file,[flipud(x-1)';zeros(padw,h)],"uchar",0,arch); + fclose(file); +endfunction
new file mode 100644 --- /dev/null +++ b/inst/bone.m @@ -0,0 +1,54 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} bone (@var{n}) +## Create color colormap. +## (a gray colormap with a light blue tone) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = bone (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("bone: argument must be a scalar"); + endif + else + usage ("bone (number)"); + endif + + if (number == 1) + map = [0, 0, 0]; + elseif (number > 1) + x = linspace (0, 1, number)'; + + r = (x < 3/4) .* (7/8 * x) + (x >= 3/4) .* (11/8 * x - 3/8); + g = (x < 3/8) .* (7/8 * x)\ + + (x >= 3/8 & x < 3/4) .* (29/24 * x - 1/8)\ + + (x >= 3/4) .* (7/8 * x + 1/8); + b = (x < 3/8) .* (29/24 * x) + (x >= 3/8) .* (7/8 * x + 1/8); + map=[r, g, b]; + else + map = []; + endif +endfunction
new file mode 100644 --- /dev/null +++ b/inst/brighten.m @@ -0,0 +1,65 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{map_out}= brighten (@var{map},@var{beta}) +## @deftypefnx {Function File} @var{map_out}= brighten (@var{beta}) +## darkens or brightens the given colormap. +## If the @var{map} argument is omitted, the function is applied to the +## current colormap. +## Should the resulting colormap @var{map_out} not be assigned, it will be +## written to the current colormap. +## The argument @var{beta} should be a scalar between -1 and 1, +## where a negative value darkens and a positive value brightens +## the colormap. +## +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 05. March 2000 + +function [Rmap] = brighten (m, beta) + + if (nargin == 1) + beta = m; + m = colormap; + + elseif (nargin == 2) + if ( (!is_matrix (m)) || (size (m, 2) != 3) ) + error ("brighten(map,beta) map must be a matrix of size nx3."); + endif + + else + usage ("brighten(...) number of arguments must be 1 or 2."); + endif + + if ( (!is_scalar (beta)) || (beta <= -1) || (beta >= 1) ) + error ("brighten(...,beta) beta must be a scalar in the range (-1,1)."); + endif + + if (beta > 0) + gamma = 1 - beta; + else + gamma = 1 / (1 + beta); + endif + + if (nargout == 0) + colormap (m .^ gamma); + else + Rmap = m .^ gamma; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/bwarea.m @@ -0,0 +1,57 @@ +## Copyright (C) 2005 Søren Hauberg +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{total}= bwarea(@var{bw}) +## Estimates the area of the "on" pixels of @var{bw}. +## If @var{bw} is a binary image "on" pixels are defined as pixels +## valued 1. If @var{bw} is a grayscale image "on" pixels is defined +## as pixels with values larger than zero. +## This algorithm is not the same as counting the number of "on" +## pixels as it tries to estimate the area of the original object +## and not the image object. +## @end deftypefn + +## Author: Søren Hauberg <hauberg at gmail dot com> +## +## 2005-06-05 Søren Hauberg <hauberg at gmail dot com> +## * Initial revision + + +function total = bwarea(bw) + if (isgray(bw)) + bw = (bw > 0); + endif + + if (!isbw(bw)) + error("input image muste be either binary or gray scale.\n"); + endif + + four = ones(2); + two = diag([1 1]); + + fours = conv2(bw, four); + twos = conv2(bw, two); + + nQ1 = sum(fours(:) == 1); + nQ3 = sum(fours(:) == 3); + nQ4 = sum(fours(:) == 4); + nQD = sum(fours(:) == 2 & twos(:) != 1); + nQ2 = sum(fours(:) == 2 & twos(:) == 1); + + total = 0.25*nQ1 + 0.5*nQ2 + 0.875*nQ3 + nQ4 + 0.75*nQD; + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/bwborder.m @@ -0,0 +1,35 @@ +## Copyright (C) 2000 Etienne Grossmann +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## b = bwborder(im) +## +## b is the borders in the 0-1 matrix im. 4-neighborhood is considered. +## +## A pixel is on the border if it is set in im, and it has at least one +## neighbor that is not set. + +## Author: Etienne Grossmann <etienne@cs.uky.edu> +## Last modified: January 2000 + +function b = bwborder(im) + +[R,C]=size(im); + +b = im & ... + !([im(2:R,:) ; zeros(1,C) ] & ... + [zeros(1,C); im(1:R-1,:) ] & ... + [im(:,2:C) , zeros(R,1) ] & ... + [zeros(R,1), im(:,1:C-1)] ) ;
new file mode 100644 --- /dev/null +++ b/inst/bweuler.m @@ -0,0 +1,102 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{eul} = } bweuler (@var{BW},@var{n}) +## Calculates the Euler number of a binary image +## +## eul=bweuler(BW,n) calculates the Euler number @var{eul} of a binary +## image @var{BW}, which is a scalar whose value is the total number of +## objects in an image minus the number of holes. +## +## @var{n} can have the values: +## @table @code +## @item 4 +## bweuler will use 4-connected neighbourhood definition. +## @item 8 +## bweuler will use 8-connected neighbourhood definition. This is the +## default value. +## @end table +## +## This function uses Bit Quads as described in "Digital Image +## Processing" to calculate euler number. +## +## References: +## W. K. Pratt, "Digital Image Processing", 3rd Edition, pp 593-595 +## +## @end deftypefn +## @seealso qtgetblk + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function eul = bweuler(BW, n) + if(nargin<1 || nargin>2) + usage("eul=bweuler(BW,n)"); + endif + if(nargin<2) + n=8; + endif + + ## q1lut=makelut(inline("sum(x(:))==1","x"),2); + ## q3lut=makelut(inline("sum(x(:))==3","x"),2); + ## qdlut=makelut(inline("all((x==eye(2))(:))||all((x==fliplr(eye(2)))(:))","x"),2); + ## lut_4=(q1lut-q3lut+2*qdlut)/4; # everything in one lut will be quicker + ## lut_8=(q1lut-q3lut-2*qdlut)/4; + ## we precalculate this... + if(n==8) + lut=[0;.25;.25;0;.25;0;-.5;-.25;.25;-.5;0;-.25;0;-.25;-.25;0]; + elseif(n==4) + lut=[0;.25;.25;0;.25;0;.5;-.25;.25;.5;0;-.25;0;-.25;-.25;0]; + else + error("bweuler: n can only be 4 or 8."); + endif + + eul=sum(applylut(BW,lut)(:)); +endfunction + +%!demo +%! A=zeros(9,10); +%! A([2,5,8],2:9)=1; +%! A(2:8,[2,9])=1 +%! bweuler(A) +%! # Euler number (objects minus holes) is 1-2=-1 in an 8-like object + +%!test +%! A=zeros(10,10); +%! A(2:9,3:8)=1; +%! A(4,4)=0; +%! A(8,8)=0; # not a hole +%! A(6,6)=0; +%! assert(bweuler(A),-1); + +%!# This will test if n=4 and n=8 behave differently +%!test +%! A=zeros(10,10); +%! A(2:4,2:4)=1; +%! A(5:8,5:8)=1; +%! assert(bweuler(A,4),2); +%! assert(bweuler(A,8),1); +%! assert(bweuler(A),1); + +% $Log$ +% Revision 1.1 2006/08/20 12:59:31 hauberg +% Changed the structure to match the package system +% +% Revision 1.2 2005/07/03 01:10:19 pkienzle +% Try to correct for missing newline at the end of the file +% +% Revision 1.1 2004/08/15 19:33:20 jmones +% bweuler: Calculates the Euler number of a binary image
new file mode 100644 --- /dev/null +++ b/inst/bwlabel.m @@ -0,0 +1,231 @@ +## Copyright (C) 2000 Etienne Grossmann +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## [im2,npix,bb] = bwlabel(im, mins, maxs, verbose) +## +## Find the connected regions of an image. +## +## im : RxC 0-1 matrix +## +## im2 : RxC int matrix in which the connected regions of im have been +## numbered. 4-neighborhoods are considered. +## +## npix : 1xQ int number of pixel in each region +## +## bb : 4xQ int bounding boxes of the regions. Rows are minrow, +## maxrow, mincol, maxcol. +## +## Options : +## +## mins : Minimum size of the regions (set to zero for no minimum) +## maxs : Maximum size of the regions (set to zero for no maximum) +## verbose : Level of output comments in range 0 to 2. +## + +## Author: Etienne Grossmann <etienne@cs.uky.edu> +## Last modified: July 2002 +## + +## Modified by David Fletcher <david@megapico.co.uk> to avoid artificially +## separate regions which actually touch (as indicated when "prudent" is set) +## through addition of lrow update within loop over touching regions. Also +## removed "sayif" function references, and call to read_options. Enabled +## options, setting of output verbosity. "Prudent" is left in place, but +## should no longer find any errors. + +function [im2,npix,bb] = bwlabel(im, mins, maxs, verbose) + + if (nargin == 1) + mins = 0; + maxs = 0; + prudent = 1; + verbose = 0; + elseif (nargin == 2) + maxs = 0; + prudent = 1; + verbose = 0; + elseif (nargin == 3) + prudent = 1; + verbose = 0; + elseif ((nargin == 4) && (verbose >= 0) && (verbose <= 2)) + prudent = 1; + else + usage ("bwlabel2(im, mins, maxs, verbose)"); + endif + +if any(im(:)&im(:)!=1), + printf("bwlabel : im is not binary\n"); + return +end + + +[R,C]=size(im); +tr = 0 ; + # Loop as little as possible +if R<C, tr = 1; im = im' ; [R,C]=size(im); end + +gsize = 100 ; # Predicted number of slices + +im2 = zeros(R,C); + # find horizontal up/down going edges +imup = max(im2, diff([zeros(1,C);im])) ; +imdo = -min(im2, diff([im;zeros(1,C)])) ; + +im2 = ones(R,C); +###################################################################### +## Find connected regions ############################################ + +rc = 1 ; # Counter of region slices + +rnum = ones(1,gsize); # List of labels of each slice +npix = zeros(1,gsize); # Sizes of regions (actual size is in + # region's first slice) +bb = zeros(4,gsize); # Bounding boxes + +if (verbose >= 1) printf("bwlabel : There will be %i loops ... \n%5i ",C,0) ; endif; + +lrow = zeros(R,1); # Last treated image column + +for i=1:C, + t1 = find(imup(:,i)) ; + t2 = find(imdo(:,i)) ; + + nrow = zeros(R,1); # Next row + + for j = 1:rows(t1(:)) , # Loop over slices of i'th column + + rc++ ; # rc = number of current slice. + im2(t1(j):t2(j),i) = rc ; + # Slices from previous column that touch + # this slice. + rr = create_set(lrow(t1(j):t2(j))) ; + if !isempty(rr) && !rr(1), rr = rr(2:length(rr)) ; end + + if rc>size(rnum,2), # Get more space (uncertain effect on + # speed; avoids resizing rnum and npix) + tmp = 2*(ceil(C*rc/i)-rc+1+rows(t1(:))-j) ; + if (verbose == 2) printf("bwlabel : (i=%i) Foreseeing %i more regions\n",i,tmp); endif; + rnum = [ rnum, ones(1,tmp) ] ; + npix = [ npix,zeros(1,tmp) ] ; + bb = [ bb,zeros(4,tmp) ] ; + end + + if isempty(rr), # New region + if (verbose == 2) printf("bwlabel : creating region %i\n",rc); endif; + + r0 = rc ; # r0 = number of the region + + bb(1,r0) = t1(j) ; + bb(2,r0) = t2(j) ; + bb(3:4,r0) = i ; + + else # Add to already existing region ##### + + r0 = rnum(rr(1)) ; + [i, j, r0]; + + bb(1,r0) = min(bb(1,r0),t1(j)) ; + bb(2,r0) = max(bb(2,r0),t2(j)) ; + bb(4,r0) = i ; + + # Touches region r0 + if (verbose == 2) printf("bwlabel : adding to region %i\n",r0); endif; + + # Touches other regions too + for k = rr(find(rr!=r0)), # Loop over other touching regions, that + # should be merged to the first. + if (verbose == 2) printf("bwlabel : merging regions %i and %i\n",k,r0); endif; + rnum(find(rnum==k)) = r0 ; + lrow(find(lrow==k)) = r0 ; ##Update lrow for next comparsion loop + npix(r0) = npix(r0) + npix(k) ; + bb([1,3],r0) = min(bb([1,3],r0)',bb([1,3],k)')' ; + bb([2,4],r0) = max(bb([2,4],r0)',bb([2,4],k)')' ; + end + + end # End of add to already existing region + ## if r0==259 && i==39,"r0==259",keyboard;end + rnum(rc) = r0 ; + + npix(r0) = npix(r0) + 1+t2(j)-t1(j) ; + + nrow(t1(j):t2(j)) = r0 ; + end # End of looping over slices + lrow = nrow ; + if (verbose >= 1) + printf("."); + if (!rem(i,70) && i<C) printf("\n%5i ",i); end + end +end # End of looping over columns + +if (verbose >= 1) printf("\n"); endif; + +keep = ones(1,rc) ; + +if mins, keep = keep & (npix(rnum(1:rc))>=mins) ; end +if maxs, keep = keep & (npix(rnum(1:rc))<=maxs) ; end +keep(1) = 1 ; +keep = find(keep) ; # Indices of slices to be kept + +foo = create_set(rnum(keep)) ; # Indices of regions to be kept +nr = prod(size(foo)) ; # Number of regions (including bg) +## lrow = zeros(1,nr) ; +tmp = zeros(1,rc) ; +tmp(foo) = 0:nr-1 ; + +bar = zeros(1,rc) ; +bar(keep) = tmp(rnum(keep)) ; + +## keyboard + +im2 = reshape(bar(im2),R,C) ; + +npix = npix(foo(2:nr)); +bb = bb(:,foo(2:nr)); + +if 0, # Draw bb on the image (will ruin + # coherence) + for i=1:nr-1, + im2([bb(1,i),bb(2,i)] ,bb(3,i):bb(4,i) ) = i ; + im2( bb(1,i):bb(2,i) ,[bb(3,i),bb(4,i)]) = i ; + end +end + +## keyboard +if prudent, + + if (verbose >= 1) printf("bwlabel : Checking coherence\n"); endif; + + hcontact = im2 & im2!=[im2(:,2:C),zeros(R,1)] & [im2(:,2:C),zeros(R,1)] ; + vcontact = im2 & im2!=[im2(2:R,:);zeros(1,C)] & [im2(2:R,:);zeros(1,C)] ; + ok = 1 ; + if (any(hcontact(:))) + if (verbose == 2) [x,y] = find(hcontact) endif; + ok = 0 ; + printf("bwlabel: Whoa! Found horizontally connected separated regions\n"); + end + if (any(vcontact(:))) + if (verbose == 2)[x,y] = find(vcontact) endif; + ok = 0 ; + printf("bwlabel: Whoa! Found vertically connected separated regions\n"); + end + if !ok, keyboard ; end +end + +## Eventually transpose result +if tr, + im2 = im2' ; + bb = bb([3,4,1,2],:); +end
new file mode 100644 --- /dev/null +++ b/inst/bwmorph.m @@ -0,0 +1,614 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{BW2} = } bwmorph (@var{BW},@var{operation}) +## @deftypefnx {Function File} {@var{BW2} = } bwmorph (@var{BW},@var{operation},@var{n}) +## Perform a morphological operation on a binary image +## +## BW2=bwmorph(BW,operation) performs a morphological operation +## specified by @var{operation} on binary image @var{BW}. All possible +## operations and their meaning are specified in a table below. +## +## BW2=bwmorph(BW,operation,n) performs a morphological operation +## @var{n} times. Keep in mind that it has no sense to apply some +## operations more than once, since some of them return the same result +## regardless how many iterations we request. Those return a warning if +## are called with n>1 and they compute the result for n=1. +## +## @var{n}>1 is actually used for the following operations: diag, +## dilate, erode, majority, shrink, skel, spur, thicken and thin. +## +## @table @code +## @item 'bothat' +## Performs a bottom hat operation, a closing operation (which is a +## dilation followed by an erosion) and finally substracts the original +## image. +## +## @item 'bridge' +## Performs a bridge operation. Sets a pixel to 1 if it has two nonzero +## neighbours which are not connected, so it "bridges" them. There are +## 119 3-by-3 patterns which trigger setting a pixel to 1. +## +## @item 'clean' +## Performs an isolated pixel remove operation. Sets a pixel to 0 if all +## of its eight-connected neighbours are 0. +## +## @item 'close' +## Performs closing operation, which is a dilation followed by erosion. +## It uses a ones(3) matrix as structuring element for both operations. +## +## @item 'diag' +## Performs a diagonal fill operation. Sets a pixel to 1 if that +## eliminates eight-connectivity of the background. +## +## @item 'dilate' +## Performs a dilation operation. It uses ones(3) as structuring element. +## +## @item 'erode' +## Performs an erosion operation. It uses ones(3) as structuring element. +## +## @item 'fill' +## Performs a interior fill operation. Sets a pixel to 1 if all +## four-connected pixels are 1. +## +## @item 'hbreak' +## Performs a H-break operation. Breaks (sets to 0) pixels that are +## H-connected. +## +## @item 'majority' +## Performs a majority black operation. Sets a pixel to 1 if five +## or more pixels in a 3-by-3 window are 1. If not it is set to 0. +## +## @item 'open' +## Performs an opening operation, which is an erosion followed by a +## dilation. It uses ones(3) as structuring element. +## +## @item 'remove' +## Performs a iterior pixel remove operation. Sets a pixel to 0 if +## all of its four-connected neighbours are 1. +## +## @item 'shrink' +## Performs a shrink operation. Sets pixels to 0 such that an object +## without holes erodes to a single pixel (set to 1) at or near its +## center of mass. An object with holes erodes to a connected ring lying +## midway between each hole and its nearest outer boundary. It preserves +## Euler number. +## +## @item 'skel' +## Performs a skeletonization operation. It calculates a "median axis +## skeleton" so that points of this skeleton are at the same distance of +## its nearby borders. It preserver Euler number. Please read +## compatibility notes for more info. +## +## It uses the same algorithm as skel-pratt but this could change for +## compatibility in the future. +## +## @item 'skel-lantuejol' +## Performs a skeletonization operation as described in Gonzalez & Woods +## "Digital Image Processing" pp 538-540. The text references Lantuejoul +## as authour of this algorithm. +## +## It has the beauty of being a clean and simple approach, but skeletons +## are thicker than they need to and, in addition, not guaranteed to be +## connected. +## +## This algorithm is iterative. It will be applied the minimum value of +## @var{n} times or number of iterations specified in algorithm +## description. It's most useful to run this algorithm with @code{n=Inf}. +## +## @item 'skel-pratt' +## Performs a skeletonization operation as described by William K. Pratt +## in "Digital Image Processing". +## +## @item 'spur' +## Performs a remove spur operation. It sets pixel to 0 if it has only +## one eight-connected pixel in its neighbourhood. +## +## @item 'thicken' +## Performs a thickening operation. This operation "thickens" objects +## avoiding their fusion. Its implemented as a thinning of the +## background. That is, thinning on negated image. Finally a diagonal +## fill operation is performed to avoid "eight-connecting" objects. +## +## @item 'thin' +## Performs a thinning operation. When n=Inf, thinning sets pixels to 0 +## such that an object without holes is converted to a stroke +## equidistant from its nearest outer boundaries. If the object has +## holes it creates a ring midway between each hole and its near outer +## boundary. This differ from shrink in that shrink converts objects +## without holes to a single pixels and thin to a stroke. It preserves +## Euler number. +## +## @item 'tophat' +## Performs a top hat operation, a opening operation (which is an +## erosion followed by a dilation) and finally substracts the original +## image. +## @end table +## +## Some useful concepts to understant operators: +## +## Operations are defined on 3-by-3 blocks of data, where the pixel in +## the center of the block. Those pixels are numerated as follows: +## +## @multitable @columnfractions 0.05 0.05 0.05 +## @item X3 @tab X2 @tab X1 +## @item X4 @tab X @tab X0 +## @item X5 @tab X6 @tab X7 +## @end multitable +## +## @strong{Neighbourhood definitions used in operation descriptions:} +## @table @code +## @item 'four-connected' +## It refers to pixels which are connected horizontally or vertically to +## X: X1, X3, X5 and X7. +## @item 'eight-connected' +## It refers to all pixels which are connected to X: X0, X1, X2, X3, X4, +## X5, X6 and X7. +## @end table +## +## @strong{Compatibility notes:} +## @table @code +## @item 'fill' +## Checking MATLAB behaviour is needed because its documentation doesn't +## make clear if it creates a black pixel if all eight-connected pixels +## are black or if four-connected suffice (as we do currently following +## Pratt's book). +## @item 'skel' +## Algorithm used here is described in Pratt's book. When applying it to +## the "circles" image in MATLAB documentation, results are not the +## same. Perhaps MATLAB uses Blum's algoritm (for further info please +## read comments in code). +## @item 'skel-pratt' +## This option is not available in MATLAB. +## @item 'skel-lantuejoul' +## This option is not available in MATLAB. +## @item 'thicken' +## This implementation also thickens image borders. This can easily be +## avoided i necessary. MATLAB documentation doesn't state how it behaves. +## @end table +## +## References: +## W. K. Pratt, "Digital Image Processing" +## Gonzalez and Woods, "Digital Image Processing" +## +## @end deftypefn +## @seealso dilate erode makelut applylut + + +## TODO: As soon as Octave doesn't segfault when assigning values to a +## TODO: bool matrix, remove all conversions from lut to logical and +## TODO: just create it as a logical from the beginning. + +## TODO: n behaviour should be tested in all cases for compatibility. + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function BW2 = bwmorph(BW, operation, n) + if(nargin<2 || nargin>3) + usage("BW2=bwmorph(BW, operation [,n])"); + endif + if(nargin<3) + n=1; + endif + if(n<0) + error("bwmorph: n should be > 0"); + elseif(n==0) ## we'll just return the same matrix (check this!) + BW2=BW; + endif + + ## post processing command + postcmd=""; + + switch(operation) + case('bothat') + se=ones(3); + BW2=erode(dilate(BW, se), se)-BW; + if(n>1) + ## TODO: check if ignoring n>1 is ok. Should I just ignore it + ## TODO: without a warning? + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('bridge') + ## see __bridge_lut_fun__ for rules + ## lut=makelut("__bridge_lut_fun__",3); + lut=logical([0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;0;0;0;0;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + BW2=applylut(BW, lut); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('clean') + ## BW(j,k)=X&&(X0||X1||...||X7) + ## lut=makelut(inline("x(2,2)&&any((x.*[1,1,1;1,0,1;1,1,1])(:))","x"),3); + ## which is the same as... + lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + lut(17)=0; ## isolated to 0 + ## I'd prefer to create lut directly as a logical, but assigning a + ## value to a logical segfaults 2.1.57. We'll change it as soon as + ## it works. + BW2=applylut(BW, logical(lut)); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('close') + se=ones(3); + BW2=erode(dilate(BW, se), se); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('diag') + ## see __diagonal_fill_lut_fun__ for rules + ## lut=makelut("__diagonal_fill_lut_fun__",3); + lut=logical([0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;1;1;0;0;0;0;0;0;1;1;0;0;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + cmd="BW2=applylut(BW, lut);"; + + + case('dilate') + cmd="BW2=dilate(BW, ones(3));"; + + case('erode') + cmd="BW2=erode(BW, ones(3));"; + + case('fill') + ## lut=makelut(inline("x(2,2)||(sum((x&[0,1,0;1,0,1;0,1,0])(:))==4)","x"),3); + ## which is the same as... + lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + ## 16 exceptions + lut([171,172,175,176,235,236,239,240,427,428,431,432,491,492,495,496])=1; + BW2=applylut(BW, logical(lut)); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + + case('hbreak') + ## lut=makelut(inline("x(2,2)&&!(all(x==[1,1,1;0,1,0;1,1,1])||all(x==[1,0,1;1,1,1;1,0,1]))","x"),3); + ## which is the same as + lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + lut([382,472])=0; ## the 2 exceptions + BW2=applylut(BW, logical(lut)); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('majority') + ## lut=makelut(inline("sum((x&ones(3,3))(:))>=5"),3); + lut=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;0;0;1;0;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + cmd="BW2=applylut(BW, lut);"; + + case('open') + se=ones(3); + BW2=dilate(erode(BW, se), se); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('remove') + ## lut=makelut(inline("x(2,2)&&!(sum((x&[0,1,0;1,1,1;0,1,0])(:))==5)","x"),3); + lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + ## 16 qualifying patterns + lut([187,188,191,192,251,252,255,256,443,444,447,448,507,508,511,512])=0; + BW2=applylut(BW, logical(lut)); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + case('shrink') + ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"S"); + lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;1;0;1;1;1;1;0;1;0;0;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); + ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'S')","m"),3); + lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;0;1;0;0;0;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;0;0;0;0;0;1;1;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; + + case({'skel','skel-pratt'}) + ## WARNING: Result doesn't look as MATLAB's sample. It has been + ## WARNING: coded following Pratt's guidelines for what he calls + ## WARNING: is a "reasonably close approximation". I couldn't find + ## WARNING: any bug. + ## WARNING: Perhaps MATLAB uses Blum's algorithm (which Pratt + ## WARNING: refers to) in: H. Blum, "A Transformation for + ## WARNING: Extracting New Descriptors of Shape", Symposium Models + ## WARNING: for Perception of Speech and Visual Form, W. + ## WARNING: Whaten-Dunn, Ed. MIT Press, Cambridge, MA, 1967. + + ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"K"); + lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;1;1;1;1;0]); + + ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'K')","m"),3); + lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;0;1;0;0;0;1;0;1;1;0;0;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;0;0;0;1;1;0;0;1;1;0;0;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;0;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1;0;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;1;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; + postcmd="BW2=bwmorph(BW2,'bridge');"; + + case('skel-lantuejoul') + ## init values + se=ones(3,3); ## structuring element used everywhere + BW2=zeros(size(BW)); ## skeleton result + eBW=BW; ## eBW will hold k-times eroded BW + i=1; + while i<=n + if(!any(eBW)) ## if erosion result is 0-matrix then + break; ## we are over + endif + BW2|=eBW-dilate(erode(eBW, se), se); ## eBW - opening operation on eBW + ## contributes to skeleton + eBW=erode(eBW,se); + i++; + endwhile + return; ## no general loop in this case + + case('spur') + ## lut=makelut(inline("xor(x(2,2),(sum((x&[0,1,0;1,0,1;0,1,0])(:))==0)&&(sum((x&[1,0,1;0,0,0;1,0,1])(:))==1)&&x(2,2))","x"),3); + ## which is the same as + lut=repmat([zeros(16,1);ones(16,1)],16,1); ## identity + lut([18,21,81,273])=0; ## 4 qualifying patterns + lut=logical(lut); + cmd="BW2=applylut(BW, lut);"; + + case('thicken') + ## This implementation also "thickens" the border. To avoid this, + ## a simple solution could be to add a border of 1 to the reversed + ## image. + BW2=bwmorph(!BW,'thin',n); + BW2=bwmorph(BW2,'diag'); + return; + + case('thin') + ## lut1=makelut("__conditional_mark_patterns_lut_fun__",3,"T"); + lut1=logical([0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;1;1;0;0;1;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;1;1;0;1;1;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;0;0;0;0;0;0;0;0; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;1;1;0;1;0;0;0;1; + 0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;1;0;1;1;1;1;0;0;1;1;0;0]); + ## lut2=makelut(inline("!m(2,2)||__unconditional_mark_patterns_lut_fun__(m,'T')","m"),3); + lut2=logical([1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;1;1;0;1;0;1;1;0;0;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;0;0;0;0;1;1;0;0;1;0; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;1;1;1;0;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;0;0;1;0;1;0;0;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;0;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;0;1;0;0;1;0;1;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;0;1;0;1;1;1;0;1;0;1;0;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;0;1;0;0;1;0;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1; + 1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1]); + cmd="BW2=BW&applylut(applylut(BW, lut1), lut2);"; + + + case('tophat') + se=ones(3); + BW2=BW-dilate(erode(BW, se), se); + if(n>1) + ## TODO: check if ignoring n>1 is ok. + disp("WARNING: n>1 has no sense here. Using n=1. Please fill a bug if you think this behaviour is not correct"); + endif + return; + + + otherwise + error("bwmorph: unknown operation type requested."); + endswitch + + ## we use this assignment because of the swap operation inside the + ## while. + BW2=BW; + + ## if it doesn't change we don't need to process it further + i=1; + while(i<=n) ## for wouldn't work because n can be Inf + [BW,BW2]=swap(BW,BW2); + eval(cmd); + if(all((BW2==BW)(:))) + break + endif + i+=1; + endwhile + + ## process post processing commands if needed + if(postcmd!="") + eval(postcmd); + endif + +endfunction + + +%!demo +%! bwmorph(ones(11),'shrink', Inf) +%! # Should return 0 matrix with 1 pixel set to 1 at (6,6) + +## TODO: code tests + + +## Test skel-lantuejoul using Gozalez&Woods example (fig 8.39) +%!shared slBW, rslBW +%! uint8(0); # fail for 2.1.57 or less instead of crashing later +%! slBW=logical(zeros(12,7)); +%! slBW(2,2)=true; +%! slBW(3:4,3:4)=true; +%! rslBW=slBW; +%! slBW(5:6,3:5)=true; +%! slBW(7:11,2:6)=true; +%! rslBW([6,7,9],4)=true; + +%!assert(bwmorph(slBW,'skel-lantuejoul',1),[rslBW(1:5,:);logical(zeros(7,7))]); +%!assert(bwmorph(slBW,'skel-lantuejoul',2),[rslBW(1:8,:);logical(zeros(4,7))]); +%!assert(bwmorph(slBW,'skel-lantuejoul',3),rslBW); +%!assert(bwmorph(slBW,'skel-lantuejoul',Inf),rslBW); + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:32 hauberg +% Changed the structure to match the package system +% +% Revision 1.6 2004/09/16 02:14:40 pkienzle +% Use frivolous uint8() call to block tests for version 2.1.57 and earlier +% +% Revision 1.5 2004/09/15 20:36:57 jmones +% logical(1) => true +% +% Revision 1.4 2004/09/15 20:00:00 jmones +% Updated tests to match Gonzalez&Woods example +% +% Revision 1.3 2004/09/15 13:51:10 pkienzle +% Use logical in tests; reduce number of shared variables in tests. +% +% Revision 1.2 2004/09/01 22:35:47 jmones +% Added Lantuejoul skeletonizing algorithm from Gonzalez&Woods +% +% Revision 1.1 2004/08/15 19:47:04 jmones +% bwmorph added: Perform a morphological operation on a binary image +% +%
new file mode 100644 --- /dev/null +++ b/inst/bwselect.m @@ -0,0 +1,40 @@ +function [imout, idx] = bwselect( im, cols, rows, connect ) +# BWSELECT: select connected regions in a binary image +# [imout, idx] = bwselect( im, cols, rows, connect ) +# +# im -> binary input image +# [cols,rows] -> vectors of starting points (x,y) +# connect -> connectedness 4 or 8. default is 8 +# imout -> the image of all objects in image im that overlap +# pixels in (cols,rows) +# idx -> index of pixels in imout + +# Copyright (C) 1999 Andy Adler +# This code has no warrany whatsoever. +# Do what you like with this code as long as you +# leave this copyright in place. +# +# $Id$ + +if nargin<4 + connect= 8; +end + +[jnk,idx]= bwfill( ~im, cols,rows, connect ); + +imout= zeros( size(jnk) ); +imout( idx ) = 1; + +# +# $Log$ +# Revision 1.1 2006/08/20 12:59:32 hauberg +# Changed the structure to match the package system +# +# Revision 1.1 2002/03/17 02:38:52 aadler +# fill and edge detection operators +# +# Revision 1.1 1999/06/08 17:06:01 aadler +# Initial revision +# +# +
new file mode 100644 --- /dev/null +++ b/inst/cmpermute.m @@ -0,0 +1,127 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{Y}, @var{newmap}] = } cmpermute (@var{X},@var{map}) +## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] = } cmpermute (@var{X},@var{map},@var{index}) +## Reorders colors in a colormap +## +## @code{[Y,newmap]=cmpermute(X,map)} rearranges colormap @var{map} +## randomly returning colormap @var{newmap} and generates indexed image +## @var{Y} so that it mantains correspondence between indices and the +## colormap from original indexed image @var{X} (both image and colormap +## pairs produce the same result). +## +## @code{[Y,newmap]=cmpermute(X,map,index)} behaves as described above +## but instead of sorting colors randomly, it uses @var{index} to define +## the order of the colors in the new colormap. +## +## @strong{Note:} @code{index} shouldn't have repeated elements, this +## function won't explicitly check this, but it will fail if it has. +## +## @end deftypefn + + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function [Y, newmap] = cmpermute(X, map, index) + switch(nargin) + case(2) + index=randperm(rows(map)); + case(3) + if(!isvector(index) || length(index)!=rows(map)) + error("cmpermute: invalid parameter index."); + endif + otherwise + usage("[Y, newmap] = cmpermute(X, map [, index])"); + endswitch + + ## new colormap + newmap=map(index,:); + + ## build reverse index + rindex = zeros(size(index)); + rindex(index) = 1:length(index); + + ## readapt indices + if(isa(X,"uint8")) + rindex=uint8(rindex-1); + ## 0-based indices + Y=rindex(double(X)+1); + else + Y=rindex(X); + endif +endfunction + + +%!demo +%! [Y,newmap]=cmpermute([1:4],hot(4),4:-1:1) +%! # colormap will be arranged in reverse order (so will image) + +%!shared X,map +%! X=magic(16); +%! [X,map]=cmunique(X); + +%!test # random permutation, 0-based index +%! [Y,newmap]=cmpermute(X,map); +%! # test we didn't lose colors +%! assert(sort(map),sortrows(newmap)); +%! # test if images are equal +%! assert(map(double(X)+1),newmap(double(Y)+1)); + +%!test # reverse map, 0-based index +%! [Y,newmap]=cmpermute(X,map,rows(map):-1:1); +%! # we expect a reversed colormap +%! assert(newmap(rows(newmap):-1:1,:),map); +%! # we expect reversed indices in image +%! assert(X,max(Y(:))-Y); + +%!shared X,map +%! X=magic(20); +%! [X,map]=cmunique(X); + +%!test # random permutation, 1-based index +%! [Y,newmap]=cmpermute(X,map); +%! # test we didn't lose colors +%! assert(sort(map),sortrows(newmap)); +%! # test if images are equal +%! assert(map(X),newmap(Y)); + +%!test # reverse map, 1-based index +%! [Y,newmap]=cmpermute(X,map,rows(map):-1:1); +%! # we expect a reversed colormap +%! assert(newmap(rows(newmap):-1:1,:),map); +%! # we expect reversed indices in image +%! assert(X,max(Y(:))+1-Y); + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:32 hauberg +% Changed the structure to match the package system +% +% Revision 1.4 2004/09/08 15:01:28 pkienzle +% Redo tests: reduce # of shared variables; force full range of uint8 +% +% Revision 1.3 2004/09/08 14:13:08 jmones +% Synchronized with cmunique. uint8 support added. Tests working for 2.1.58 +% +% Revision 1.2 2004/08/18 14:57:42 jmones +% speed improvement suggested by Paul Kienzle +% +% Revision 1.1 2004/08/17 19:18:42 jmones +% cmpermute added: Reorders colors in a colormap +% +%
new file mode 100644 --- /dev/null +++ b/inst/cmunique.m @@ -0,0 +1,206 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{Y}, @var{newmap}] = } cmunique (@var{X},@var{map}) +## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] = } cmunique (@var{RGB}) +## @deftypefnx {Function File} {[@var{Y}, @var{newmap}] = } cmunique (@var{I}) +## Finds colormap with unique colors and corresponding image +## +## @code{[Y,newmap]=cmunique(X,map)} returns an indexed image @var{y} +## along with its associated colormap @var{newmap} equivalent (which +## produce the same image) to supplied @var{X} and its colormap +## @var{map}; but eliminating any repeated rows in colormap colors and +## adjusting indices in the image matrix as needed. +## +## @code{[Y,newmap]=cmunique(RGB)} returns an indexed image @var{y} +## along with its associated colormap @var{newmap} computed from a +## true-color image @var{RGB} (a m-by-n-by-3 array), where @var{newmap} +## is the smallest colormap possible (alhough it could be as long as +## number of pixels in image). +## +## @code{[Y,newmap]=cmunique(I)} returns an indexed image @var{y} +## along with its associated colormap @var{newmap} computed from a +## intensity image @var{I}, where @var{newmap} is the smallest +## colormap possible (alhough it could be as long as number of pixels +## in image). +## +## @strong{Notes:} +## +## @var{newmap} is always a @var{m}-by-3 matrix, even if input image is +## a intensity grey-scale image @var{I} (all three RGB planes are +## assigned the same value). +## +## @var{newmap} is always of class double. If we use a RGB or intensity +## image of class uint8 or uint16, the colors in the colormap will be of +## class double in the range [0,1] (they are divided by intmax("uint8") +## and intmax("uint16") respectively. +## +## @end deftypefn + + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function [Y, newmap] = cmunique(P1, P2) + if (nargin<1 || nargin>2) + usage("[Y, newmap] = cmunique(X, map), [Y, newmap] = cmunique(RGB), [Y, newmap] = cmunique(I)"); + endif + + + if(nargin==2) + ## (X, map) case + [newmap,i,j]=unique(P2,'rows'); ## calculate unique colormap + if(isa(P1,"double")) + Y=j(P1); ## find new indices + else + Y=j(double(P1)+1); ## find new indices + endif + else + switch(size(P1,3)) + case(1) + ## I case + [newmap,i,j]=unique(P1); ## calculate unique colormap + newmap=repmat(newmap,1,3); ## get a RGB colormap + Y=reshape(j,rows(P1),columns(P1)); ## Y is j reshaped + case(3) + ## RGB case + map=[P1(:,:,1)(:), P1(:,:,2)(:), P1(:,:,3)(:)]; ## build a map with all values + [newmap,i,j]=unique(map, 'rows'); ## calculate unique colormap + Y=reshape(j,rows(P1),columns(P1)); ## Y is j reshaped + otherwise + error("cmunique: first parameter is invalid."); + endswitch + + ## if image was uint8 or uint16 we have to convert newmap to [0,1] range + if(!isa(P1,"double")) + newmap=double(newmap)/double(intmax(class(P1))); + endif + endif + + if(rows(newmap)<=256) + ## convert Y to uint8 (0-based indices then) + Y=uint8(Y-1); + endif + + +endfunction + + +%!demo +%! [Y,newmap]=cmunique([1:4;5:8],[hot(4);hot(4)]) +%! # Both rows are equal since map maps colors to the same value +%! # cmunique will give the same indices to both + + +%!# This triggers invalid first parameter +%!error(cmunique(zeros(3,3,2))); + +%!# Check that output is uint8 in short colormaps +%!test +%! [Y,newmap]=cmunique([1:4;5:8], [hot(4);hot(4)]); +%! assert(Y,uint8([0:3;0:3])); +%! assert(newmap,hot(4)); + +%!# Check that output is double in bigger +%!test +%! [Y,newmap]=cmunique([1:300;301:600], [hot(300);hot(300)]); +%! assert(Y,[1:300;1:300]); +%! assert(newmap,hot(300)); + +%!# Check boundary case 256 +%!test +%! [Y,newmap]=cmunique([1:256;257:512], [hot(256);hot(256)]); +%! assert(Y,uint8([0:255;0:255])); +%! assert(newmap,hot(256)); + +%!# Check boundary case 257 +%!test +%! [Y,newmap]=cmunique([1:257;258:514], [hot(257);hot(257)]); +%! assert(Y,[1:257;1:257]); +%! assert(newmap,hot(257)); + +%!# Random RGB image +%!test +%! RGB=rand(10,10,3); +%! [Y,newmap]=cmunique(RGB); +%! assert(RGB(:,:,1),newmap(:,1)(Y+1)); +%! assert(RGB(:,:,2),newmap(:,2)(Y+1)); +%! assert(RGB(:,:,3),newmap(:,3)(Y+1)); + +%!# Random uint8 RGB image +%!test +%! RGB=uint8(rand(10,10,3)*255); +%! RGBd=double(RGB)/255; +%! [Y,newmap]=cmunique(RGB); +%! assert(RGBd(:,:,1),newmap(:,1)(Y+1)); +%! assert(RGBd(:,:,2),newmap(:,2)(Y+1)); +%! assert(RGBd(:,:,3),newmap(:,3)(Y+1)); + +%!# Random uint16 RGB image +%!test +%! RGB=uint16(rand(10,10,3)*65535); +%! RGBd=double(RGB)/65535; +%! [Y,newmap]=cmunique(RGB); +%! assert(RGBd(:,:,1),newmap(:,1)(Y+1)); +%! assert(RGBd(:,:,2),newmap(:,2)(Y+1)); +%! assert(RGBd(:,:,3),newmap(:,3)(Y+1)); + +%!# Random I image +%!test +%! I=rand(10,10); +%! [Y,newmap]=cmunique(I); +%! assert(I,newmap(:,1)(Y+1)); +%! assert(I,newmap(:,2)(Y+1)); +%! assert(I,newmap(:,3)(Y+1)); + +%!# Random uint8 I image +%!test +%! I=uint8(rand(10,10)*256); +%! Id=double(I)/255; +%! [Y,newmap]=cmunique(I); +%! assert(Id,newmap(:,1)(Y+1)); +%! assert(Id,newmap(:,2)(Y+1)); +%! assert(Id,newmap(:,3)(Y+1)); + +%!# Random uint16 I image +%!test +%! I=uint16(rand(10,10)*65535); +%! Id=double(I)/65535; +%! [Y,newmap]=cmunique(I); +%! assert(Id,newmap(:,1)(Y+1)); +%! assert(Id,newmap(:,2)(Y+1)); +%! assert(Id,newmap(:,3)(Y+1)); + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:32 hauberg +% Changed the structure to match the package system +% +% Revision 1.4 2004/09/08 16:06:31 jmones +% Solved problem with uint8 indexing and reduced tests on types (suggested by P. Kienzle) +% +% Revision 1.3 2004/09/03 17:07:26 jmones +% Support for uint8 and uint16 types added. +% +% Revision 1.2 2004/08/17 15:48:03 jmones +% Clarified expected data for RGB images in doc +% +% Revision 1.1 2004/08/17 15:45:40 jmones +% cmunique: Finds colormap with unique colors and corresponding image +% +% + +
new file mode 100644 --- /dev/null +++ b/inst/col2im.m @@ -0,0 +1,172 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{A} = } col2im (@var{B}, [@var{m},@var{n}], [@var{mm},@var{nn}], @var{block_type}) +## @deftypefnx {Function File} {@var{A} = } col2im (@var{B}, [@var{m},@var{n}], [@var{mm},@var{nn}]) +## Rearranges matrix columns into blocks +## +## @code{A=col2im(B,[m,n],[mm,nn],block_type)} rearranges columns of +## matrix @var{B} intro blocks in a way controlled by @var{block_type} +## param, which can take the following values: +## +## @table @code +## @item distinct +## It uses @var{m}-by-@var{n} distinct blocks (which are not +## overlapped), and are rearranged to form a @var{mm}-by-@var{nn} matrix +## @var{A}. @var{B}'s height must be @var{m}*@var{n} and @code{col2im} +## rearranges each column to a @var{m}-by-@var{n} block and uses them to +## fill the whole matrix in left-to-right and then up-to-down order. +## @item sliding +## Is uses @var{m}-by-@var{n} sliding blocks. It rearranges row vector +## @var{B} to a (@var{mm}-@var{m}+1)-by-(@var{nn}-@var{n}+1) matrix +## @var{A}. @var{B} must be a +## 1-by-(@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1). +## @end table +## +## @code{A=col2im(B,[m,n],[mm,nn])} takes @code{distinct} as a default +## value for @var{block_type}. +## +## @end deftypefn +## @seealso{im2col} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function A = col2im(B, sblock, sb, block_type) + if(nargin<3 || nargin>4) + usage("A=col2im(B, [m,n], [mm,nn] [, block_type])"); + endif + + if(nargin!=4) + block_type='sliding'; + endif + + ## common checks + if(!ismatrix(B)) + error("col2im: B should be a matrix (or vector)."); + endif + if(!isvector(sblock) || length(sblock)!=2) + error("col2im: expected [m,n] as second parameter."); + endif + if(!isvector(sb) || length(sb)!=2) + error("col2im: expected [mm,nn] as third parameter."); + endif + + m=sblock(1); + n=sblock(2); + mm=sb(1); + nn=sb(2); + + switch(block_type) + case('distinct') + if(rows(B)!=m*n) + error("col2im: B height must be m*n for 'distinct' block_type."); + endif + if(rem(mm,m)!=0) + error("col2im: mm should be multiple of m"); + endif + if(rem(nn,n)!=0) + error("col2im: nn should be multiple of n"); + endif + mt=mm/m; + nt=nn/n; + if(columns(B)<mt*nt) + error("col2im: B's width is too small (should be mm*nn/(m*m))."); + endif + c=1; + for i=1:mt + ## TODO: check if we can horzcat([],uint8([10;11])) in a + ## future Octave version > 2.1.58 in order to deuglify this! + r=reshape(B(:,c),m,n); + c+=1; + for j=2:nt + r=horzcat(r, reshape(B(:,c),m,n)); + c+=1; + endfor + if(i==1) ## this workarrounds a bug in ver<=2.1.57 cat implementation + A=r; + else + A=vertcat(A,r); + endif + endfor + + case('sliding') + if(!all(size(B)==[1,(mm-m+1)*(nn-n+1)])) + error("col2im: wrong B size. Should be 1-by-(mm-m+1)*(nn-n+1)."); + endif + A=reshape(B, mm-m+1, nn-n+1); + + otherwise + error("col2im: invalid block_type."); + endswitch + +endfunction + +%!demo +%! A=[1:10;11:20;21:30;31:40] +%! B=im2col(A,[2,5],'distinct') +%! C=col2im(B,[2,5],[4,10],'distinct') +%! # Divide A using distinct blocks and reverse operation + + +%!shared B, Ad +%! v=[1:10]'; +%! r=reshape(v,2,5); +%! B=[v, v+10, v+20, v+30, v+40, v+50]; +%! Ad=[r, r+10; r+20, r+30; r+40, r+50]; + +%!# bad m +%!error(col2im(B,[3,5],[6,10],'distinct')); + +%!# bad n +%!error(col2im(B,[2,3],[6,10],'distinct')); + +%!# bad mm +%!error(col2im(B,[2,5],[7,10],'distinct')); + +%!# bad nn +%!error(col2im(B,[2,5],[6,11],'distinct')); + +%!# bad block_type +%!error(col2im(B,[2,5],[6,10],'wrong_block_type')); + +%!# this should be ok +%!assert(col2im(B,[2,5],[6,10],'distinct'), Ad); + +%!# now sliding +%!assert(col2im(ones(1,(10-2+1)*(7-3+1)),[2,3],[10,7]), ones((10-2+1),(7-3+1))); +%!assert(col2im(ones(1,(10-2+1)*(7-3+1)),[2,3],[10,7],'sliding'), ones((10-2+1),(7-3+1))); + + +%!# disctint on uint8 +%!assert(col2im(uint8(B),[2,5],[6,10],'distinct'), uint8(Ad)); + +%!# now sliding on uint8 +%!assert(col2im(ones(1,(10-2+1)*(7-3+1),"uint8"),[2,3],[10,7]), ones((10-2+1),(7-3+1),"uint8")); + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:32 hauberg +% Changed the structure to match the package system +% +% Revision 1.2 2004/09/03 17:57:42 jmones +% Added support for int* and uint* types +% +% Revision 1.1 2004/08/18 14:39:07 jmones +% im2col and col2im added +% +%
new file mode 100644 --- /dev/null +++ b/inst/colfilt.m @@ -0,0 +1,94 @@ +## COLFILT Apply filter to matrix blocks +## colfilt(A,[r c],[m n],'sliding',f,...) +## For each r x c overlapping subblock of A, add a column in matrix C +## f(C,...) should return a row vector which is then reshaped into a +## a matrix of size A and returned. A is processed in chunks of size m x n. +## colfilt(A,[r c],[m n],'distinct',f,...) +## For each r x c non-overlapping subblock of A, add a column in matrix C +## f(C,...) should return a matrix of size C each column of which is +## placed back into the subblock from whence it came. A is processed +## in chunks of size m x n. +## +## The present version requires [m n], but for compatibility it should +## be optional. Use colfilt(A,[r c],size(A),...) +## +## The present version requires that [m n] divide size(A), but for +## compatibility it should work even if [m n] does not divide A. Use +## the following instead: +## [r c] = size(A); +## padA = zeros (m*ceil(r/m),n*ceil(c/n)); +## padA(1:r,1:c) = A; +## B = colfilt(padA,...); +## B = B(1:r,1:c); +## +## The present version does not handle 'distinct' + +## This software is granted to the public domain +## Author: Paul Kienzle <pkienzle@users.sf.net> + +function B = colfilt(A,filtsize,blksize,blktype,f,varargin) + + [m,n]=size(A); + r = filtsize(1); + c = filtsize(2); + mblock = blksize(1); + nblock = blksize(2); + + switch blktype + case 'sliding' + # pad with zeros + padm = (m+r-1); + padn = (n+c-1); + padA = zeros(padm, padn); + padA([1:m]+floor((r-1)/2),[1:n]+floor((c-1)/2)) = A; + padA = padA(:); + + # throw away old A to save memory. + B=A; clear A; + + # build the index vector + colidx = [0:r-1]'*ones(1,c) + padm*ones(r,1)*[0:c-1]; + offset = [1:mblock]'*ones(1,nblock) + padm*ones(mblock,1)*[0:nblock-1]; + idx = colidx(:)*ones(1,mblock*nblock) + ones(r*c,1)*offset(:)'; + clear colidx offset; + + # process the matrix, one block at a time + idxA = zeros(r*c,mblock*nblock); + tmp = zeros(mblock,nblock); + for i = 0:m/mblock-1 + for j = 0:n/nblock-1 + idxA(:) = padA(idx + (i*mblock + padm*j*nblock)); + tmp(:) = feval(f,idxA,varargin{:}); + B(1+i*mblock:(i+1)*mblock, 1+j*nblock:(j+1)*nblock) = tmp; + end + end + + case 'old-sliding' # processes the whole matrix at a time + padA = zeros(m+r-1,n+c-1); + padA([1:m]+floor(r/2),[1:n]+floor(c/2)) = A; + [padm,padn] = size(padA); + colidx = [0:r-1]'*ones(1,c) + padm*ones(r,1)*[0:c-1]; + offset = [1:m]'*ones(1,n) + padm*ones(m,1)*[0:n-1]; + idx = colidx(:)*ones(1,m*n) + ones(r*c,1)*offset(:)'; + idxA = zeros(r*c,m*n); + idxA(:) = padA(:)(idx); + B = zeros(size(A)); + B(:) = feval(f,idxA,varargin{:}); + case 'old-distinct' # processes the whole matrix at a time + if (r*floor(m/r) != m || c*floor(n/c) != n) + error("colfilt expected blocks to exactly fill A"); + endif + colidx = [0:r-1]'*ones(1,c) + m*ones(r,1)*[0:c-1]; + offset = [1:r:m]'*ones(1,n/c) + m*ones(m/r,1)*[0:c:n-1]; + idx =colidx(:)*ones(1,m*n/r/c) + ones(r*c,1)*offset(:)'; + idxA = zeros(r*c,m*n/r/c); + idxA(:) = A(:)(idx); + B = zeros(prod(size(A)),1); + B(idx) = feval(f,idxA,varargin{:}); + B = reshape(B,size(A)); + endswitch +endfunction + +%!test +%! A = reshape(1:36,6,6); +%! assert(colfilt(A,[2,2],[3,3],'sliding','sum'), conv2(A,ones(2),'same'));
new file mode 100644 --- /dev/null +++ b/inst/colorgradient.m @@ -0,0 +1,52 @@ +## M = colorgradient(C,w,n) +## Define a colour map which smoothly traverses the given colors. +## C contains the colours, one row per r,g,b value. +## w(i) is the relative length of the transition from colour i to colour i+1 +## in the entire gradient. The default is ones(rows(C)-1,1). +## n is the length of the colour map. The default is rows(colormap). +## +## E.g., +## colorgradient([0,0,1; 1,1,0; 1,0,0]) # blue -> yellow -> red +## x = linspace(0,1,200); +## imagesc(x(:,ones(30,1)))'; + +## This program is granted to the public domain. +## Author: Paul Kienzle <pkienzle@users.sf.net> + +function ret = colorgradient(C,w,n) + if nargin < 1 || nargin > 3 + usage("M = colorgradient(C,w,n)") + endif + + if nargin == 1 + n = rows(colormap); + w = ones(length(C)-1,1); + elseif nargin == 2 + if (length(w) == 1) + n = w; + w = ones(rows(C)-1,1); + else + n = rows(colormap); + endif + endif + + if (length(w)+1 != rows(C)) + error("must have one weight for each color interval"); + endif + + w = 1+round((n-1)*cumsum([0;w(:)])/sum(w)); + map = zeros(n,3); + for i=1:length(w)-1 + if (w(i) != w(i+1)) + map(w(i):w(i+1),1) = linspace(C(i,1),C(i+1,1),w(i+1)-w(i)+1)'; + map(w(i):w(i+1),2) = linspace(C(i,2),C(i+1,2),w(i+1)-w(i)+1)'; + map(w(i):w(i+1),3) = linspace(C(i,3),C(i+1,3),w(i+1)-w(i)+1)'; + endif + endfor + + if nargout == 0 + colormap(map); + else + ret = map; + endif +endfunction
new file mode 100644 --- /dev/null +++ b/inst/conndef.m @@ -0,0 +1,109 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{conn} = } conndef (@var{num_dims}, @var{type}) +## Creates a connectivity array +## +## @code{conn=conndef(num_dims,type)} creates a connectivity array +## (@var{CONN}) of @var{num_dims} dimensions and which type is defined +## by @var{type} as follows: +## @table @code +## @item minimal +## Neighbours touch the central element on a (@var{num_dims}-1)-dimensional +## surface. +## @item maximal +## Neighbours touch the central element in any way. Equivalent to +## @code{ones(repmat(3,1,@var{num_dims}))}. +## @end table +## +## @end deftypefn + + + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function conn = conndef(num_dims,conntype) + if(nargin!=2) + usage("conn=conndef(num_dims, type)"); + endif + if(num_dims<=0) + error("conndef: num_dims must be > 0"); + endif + + if(strcmp(conntype,"minimal")) + if(num_dims==1) + conn=[1;1;1]; + elseif(num_dims==2) + conn=[0,1,0;1,1,1;0,1,0]; + else + conn=zeros(repmat(3,1,num_dims)); + idx={}; + idx{1}=1:3; + for i=2:num_dims + idx{i}=2; + endfor + conn(idx{:})=1; + for i=2:num_dims + idx{i-1}=2; + idx{i}=1:3; + conn(idx{:})=1; + endfor + endif + + elseif(strcmp(conntype,"maximal")) + if(num_dims==1) + conn=[1;1;1]; + else + conn=ones(repmat(3,1,num_dims)); + endif + else + error("conndef: invalid type parameter."); + endif + +endfunction + +%!demo +%! conndef(2,'minimal') +%! % Create a 2-D minimal connectivity array + +%!assert(conndef(1,'minimal'), [1;1;1]); + +%!assert(conndef(2,'minimal'), [0,1,0;1,1,1;0,1,0]); + +%!test +%! C=zeros(3,3); +%! C(2,2,1)=1; +%! C(2,2,3)=1; +%! C(:,:,2)=[0,1,0;1,1,1;0,1,0]; +%! assert(conndef(3,'minimal'), C); + +%!assert(conndef(1,'maximal'), ones(3,1)); +%!assert(conndef(2,'maximal'), ones(3,3)); +%!assert(conndef(3,'maximal'), ones(3,3,3)); +%!assert(conndef(4,'maximal'), ones(3,3,3,3)); + + + +% $Log$ +% Revision 1.1 2006/08/20 12:59:32 hauberg +% Changed the structure to match the package system +% +% Revision 1.2 2005/07/03 01:10:19 pkienzle +% Try to correct for missing newline at the end of the file +% +% Revision 1.1 2004/08/15 19:38:44 jmones +% conndef added: Creates a connectivity array
new file mode 100644 --- /dev/null +++ b/inst/cool.m @@ -0,0 +1,51 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} cool (@var{n}) +## Create color colormap. +## (cyan to magenta) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = cool (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("cool: argument must be a scalar"); + endif + else + usage ("cool (number)"); + endif + + if (number == 1) + map = [0, 1, 1]; + elseif (number > 1) + r = (0:number - 1)' ./ (number - 1); + g = 1 - r; + b = ones (number, 1); + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/copper.m @@ -0,0 +1,52 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} copper (@var{n}) +## Create color colormap. +## (black to a light copper tone) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = copper (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("copper: argument must be a scalar"); + endif + else + usage ("copper (number)"); + endif + + if (number == 1) + map = [0, 0, 0]; + elseif (number > 1) + x = linspace (0, 1, number)'; + r = (x < 4/5) .* (5/4 * x) + (x >= 4/5); + g = 4/5 * x; + b = 1/2 * x; + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/corr2.m @@ -0,0 +1,42 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{r}= corr2 (@var{I},@var{J}) +## returns the correlation coefficient between @var{I} and @var{j}. +## @var{I,J} must be real type matrices or vectors of same size +## @end deftypefn + + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 01/08/2000 + +function r = corr2 (I, J) + + if !(nargin == 2) + usage ("corr2(I,J)"); + endif + + if !(is_matrix(I) && isreal(I) && is_matrix(J) && isreal(J)) + error("argument must be a real type matrix"); + endif + + if (size (I) != size (J)) + error("arguments must be of same size") + endif + + r = cov (I, J) / (std2(I)*std2(J)); +endfunction
new file mode 100644 --- /dev/null +++ b/inst/dilate.m @@ -0,0 +1,87 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{BW2} = } dilate (@var{BW1},@var{SE}) +## @deftypefnx {Function File} {@var{BW2} = } dilate (@var{BW1},@var{SE},@var{alg}) +## @deftypefnx {Function File} {@var{BW2} = } dilate (@var{BW1},@var{SE},...,@var{n}) +## Perform a dilation morphological operation on a binary image. +## +## BW2 = dilate(BW1, SE) returns a binary image with the result of a dilation +## operation on @var{BW1} using neighbour mask @var{SE}. +## +## For each point in @var{BW1}, dilate search its neighbours (which are +## defined by setting to 1 their in @var{SE}). If any of its neighbours +## is on (1), then pixel is set to 1. If all are off (0) then it is set to 0. +## +## Center of @var{SE} is calculated using floor((size(@var{SE})+1)/2). +## +## Pixels outside the image are considered to be 0. +## +## BW2 = dilate(BW1, SE, alg) returns the result of a dilation operation +## using algorithm @var{alg}. Only 'spatial' is implemented at the moment. +## +## BW2 = dilate(BW1, SE, ..., n) returns the result of @var{n} dilation +## operations on @var{BW1}. +## +## @end deftypefn +## @seealso{erode} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function BW2 = dilate(BW1, SE, a, b) + alg='spatial'; + n=1; + if (nargin < 1 || nargin > 4) + usage ("BW2 = dilate(BW1, SE [, alg] [, n])"); + endif + if nargin == 4 + alg=a; + n=b; + elseif nargin == 3 + if ischar(a) + alg=a; + else + n=a; + endif + endif + + if !strcmp(alg, 'spatial') + error("dilate: alg not implemented."); + endif + + # "Binarize" BW1, just in case image is not [1,0] + BW1=BW1!=0; + + for i=1:n + # create result matrix + BW1=filter2(SE,BW1)>0; + endfor + + BW2=BW1; +endfunction + +%!demo +%! dilate(eye(5),ones(2,2)) +%! % returns a thick diagonal. + + + +%!assert(dilate(eye(3),[1])==eye(3)); # using [1] as a mask returns the same value +%!assert(dilate(eye(3),[1,0,0])==[[0;0],eye(2);0,0,0]); +%!assert(dilate(eye(3),[1,0,0,0])==[[0;0],eye(2);0,0,0]); # test if center is correctly calculated on even masks + +
new file mode 100644 --- /dev/null +++ b/inst/edge.m @@ -0,0 +1,243 @@ +function [imout, thresh] = edge( im, method, thresh, param2 ) +# EDGE: find image edges +# [imout, thresh] = edge( im, method, thresh, param2 ) +# +# OUTPUT +# imout -> output image +# thresh -> output thresholds +# +# INPUT +# im -> input image (greyscale) +# thresh -> threshold value (value is estimated if not given) +# +# The following methods are based on high pass filtering the image in +# two directions, calculating a combined edge weight from and then thresholding +# +# method = 'roberts' +# filt1= [1 0 ; 0 -1]; filt2= rot90( filt1 ) +# combine= sqrt( filt1^2 + filt2^2 ) +# method = 'sobel' +# filt1= [1 2 1;0 0 0;-1 -2 -1]; filt2= rot90( filt1 ) +# combine= sqrt( filt1^2 + filt2^2 ) +# method = 'prewitt' +# filt1= [1 1 1;0 0 0;-1 -1 -1]; filt2= rot90( filt1 ) +# combine= sqrt( filt1^2 + filt2^2 ) +# method = 'kirsh' +# filt1= [1 2 1;0 0 0;-1 -2 -1]; filt2 .. filt8 are 45 degree rotations of filt1 +# combine= max( filt1 ... filt8 ) +# +# methods based on filtering the image and finding zero crossings +# +# method = 'log' -> Laplacian of Gaussians +# param2 is the standard deviation of the filter, default is 2 +# method = 'zerocross' -> generic zero-crossing filter +# param2 is the user supplied filter +# +# method = 'andy' -> my idea +# A.Adler's idea (c) 1999. somewhat based on the canny method +# Step 1: Do a sobel edge detection and to generate an image at +# a high and low threshold +# Step 2: Edge extend all edges in the LT image by several pixels, +# in the vertical, horizontal, and 45degree directions. +# Combine these into edge extended (EE) image +# Step 3: Dilate the EE image by 1 step +# Step 4: Select all EE features that are connected to features in +# the HT image +# +# Parameters: +# param2(1)==0 or 4 or 8 -> perform x connected dilatation (step 3) +# param2(2) dilatation coeficient (threshold) in step 3 +# param2(3) length of edge extention convolution (step 2) +# param2(4) coeficient of extention convolution in step 2 +# defaults = [8 1 3 3] + +# Copyright (C) 1999 Andy Adler +# This code has no warrany whatsoever. +# Do what you like with this code as long as you +# leave this copyright in place. +# +# $Id$ + +[n,m]= size(im); +xx= 2:m-1; +yy= 2:n-1; + +if strcmp(method,'roberts') || strcmp(method,'sobel') || ... + strcmp(method,'prewitt') + + + if strcmp(method,'roberts') + filt= [1 0;0 -1]/4; tv= 6; + elseif strcmp(method,'sobel') + filt= [1 2 1;0 0 0; -1 -2 -1]/8; tv= 2; + elseif strcmp(method,'prewitt') + filt= [1 1 1;0 0 0; -1 -1 -1]/6; tv= 4; + end + + imo= conv2(im, rot90(filt), 'same').^2 + conv2(im, filt, 'same').^2; + +# check to see if the user supplied a threshold +# if not, calculate one in the same way as Matlab + + if nargin<3 + thresh= sqrt( tv* mean(mean( imo(yy,xx) )) ); + end + +# The filters are defined for sqrt(imo), but since we calculated imo, compare +# to thresh ^2 + + imout= ( imo >= thresh^2 ); + +# Thin the wide edges + xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; + ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; + imout(yy,xx)= imout(yy,xx) & ( xpeak | ypeak ); + +elseif strcmp(method,'kirsch') + + filt1= [1 2 1;0 0 0;-1 -2 -1]; fim1= conv2(im,filt1,'same'); + filt2= [2 1 0;1 0 -1;0 -1 -2]; fim2= conv2(im,filt2,'same'); + filt3= [1 0 -1;2 0 -2;1 0 -1]; fim3= conv2(im,filt3,'same'); + filt4= [0 1 2;-1 0 1;-2 -1 0]; fim4= conv2(im,filt4,'same'); + + imo= reshape(max([abs(fim1(:)) abs(fim2(:)) abs(fim3(:)) abs(fim4(:))]'),n,m); + + if nargin<3 + thresh= 2* mean(mean( imo(yy,xx) )) ; + end + + imout= imo >= thresh ; + +# Thin the wide edges + xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; + ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; + imout(yy,xx)= imout(yy,xx) & ( xpeak | ypeak ); + +elseif strcmp(method,'log') || strcmp(method,'zerocross') + + if strcmp(method,'log') + if nargin >= 4; sd= param2; + else sd= 2; + end + + sz= ceil(sd*3); + [x,y]= meshgrid( -sz:sz, -sz:sz ); + filt = exp( -( x.^2 + y.^2 )/2/sd^2 ) .* ... + ( x.^2 + y.^2 - 2*sd^2 ) / 2 / pi / sd^6 ; + else + filt = param2; + end + filt = filt - mean(filt(:)); + + imo= conv2(im, filt, 'same'); + + if nargin<3 || isempty( thresh ) + thresh= 0.75* mean(mean( abs(imo(yy,xx)) )) ; + end + + zcross= imo > 0; + yd_zc= diff( zcross ); + xd_zc= diff( zcross' )'; + yd_io= abs(diff( imo ) ) > thresh; + xd_io= abs(diff( imo')') > thresh; + +# doing it this way puts the transition at the <=0 point + xl= zeros(1,m); yl= zeros(n,1); + imout= [ ( yd_zc == 1 ) & yd_io ; xl] | ... + [xl; ( yd_zc == -1 ) & yd_io ] | ... + [ ( xd_zc == 1 ) & xd_io , yl] | ... + [yl, ( xd_zc == -1 ) & xd_io ]; + +elseif strcmp(method,'canny') + error("method canny not implemented"); + +elseif strcmp(method,'andy') + + filt= [1 2 1;0 0 0; -1 -2 -1]/8; tv= 2; + imo= conv2(im, rot90(filt), 'same').^2 + conv2(im, filt, 'same').^2; + if nargin<3 || thresh==[]; + thresh= sqrt( tv* mean(mean( imo(yy,xx) )) ); + end +# sum( imo(:)>thresh ) / prod(size(imo)) + dilate= [1 1 1;1 1 1;1 1 1]; tt= 1; sz=3; dt=3; + if nargin>=4 + # 0 or 4 or 8 connected dilation + if length(param2) > 0 + if param2(1)==4 ; dilate= [0 1 0;1 1 1;0 1 0]; + elseif param2(1)==0 ; dilate= 1; + end + end + # dilation threshold + if length(param2) > 2; tt= param2(2); end + # edge extention length + if length(param2) > 2; sz= param2(3); end + # edge extention threshold + if length(param2) > 3; dt= param2(4); end + + end + fobliq= [0 0 0 0 1;0 0 0 .5 .5;0 0 0 1 0;0 0 .5 .5 0;0 0 1 0 0; + 0 .5 .5 0 0;0 1 0 0 0;.5 .5 0 0 0;1 0 0 0 0]; + fobliq= fobliq( 5-sz:5+sz, 3-ceil(sz/2):3+ceil(sz/2) ); + + xpeak= imo(yy,xx-1) <= imo(yy,xx) & imo(yy,xx) > imo(yy,xx+1) ; + ypeak= imo(yy-1,xx) <= imo(yy,xx) & imo(yy,xx) > imo(yy+1,xx) ; + + imht= ( imo >= thresh^2 * 2); # high threshold image + imht(yy,xx)= imht(yy,xx) & ( xpeak | ypeak ); + imht([1,n],:)=0; imht(:,[1,m])=0; + +% imlt= ( imo >= thresh^2 / 2); # low threshold image + imlt= ( imo >= thresh^2 / 1); # low threshold image + imlt(yy,xx)= imlt(yy,xx) & ( xpeak | ypeak ); + imlt([1,n],:)=0; imlt(:,[1,m])=0; + +# now we edge extend the low thresh image in 4 directions + + imee= ( conv2( imlt, ones(2*sz+1,1) , 'same') > tt ) | ... + ( conv2( imlt, ones(1,2*sz+1) , 'same') > tt ) | ... + ( conv2( imlt, eye(2*sz+1) , 'same') > tt ) | ... + ( conv2( imlt, rot90(eye(2*sz+1)), 'same') > tt ) | ... + ( conv2( imlt, fobliq , 'same') > tt ) | ... + ( conv2( imlt, fobliq' , 'same') > tt ) | ... + ( conv2( imlt, rot90(fobliq) , 'same') > tt ) | ... + ( conv2( imlt, flipud(fobliq) , 'same') > tt ); +# imee(yy,xx)= conv2(imee(yy,xx),ones(3),'same') & ( xpeak | ypeak ); + imee= conv2(imee,dilate,'same') > dt; # + +% ff= find( imht==1 ); +% imout = bwselect( imee, rem(ff-1, n)+1, ceil(ff/n), 8); + imout = imee; + + +else + + error (['Method ' method ' is not recognized']); + +end + + + + +# +# $Log$ +# Revision 1.1 2006/08/20 12:59:32 hauberg +# Changed the structure to match the package system +# +# Revision 1.1 2002/03/17 02:38:52 aadler +# fill and edge detection operators +# +# Revision 1.4 2000/11/20 17:13:07 aadler +# works? +# +# Revision 1.3 1999/06/09 17:29:36 aadler +# implemented 'andy' mode edge detection +# +# Revision 1.2 1999/06/08 14:26:50 aadler +# zero-cross and LoG filters work +# +# Revision 1.1 1999/06/07 21:01:38 aadler +# Initial revision +# +# + +#
new file mode 100644 --- /dev/null +++ b/inst/erode.m @@ -0,0 +1,89 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{BW2} = } erode (@var{BW1},@var{SE}) +## @deftypefnx {Function File} {@var{BW2} = } erode (@var{BW1},@var{SE},@var{alg}) +## @deftypefnx {Function File} {@var{BW2} = } erode (@var{BW1},@var{SE},...,@var{n}) +## Perform an erosion morphological operation on a binary image. +## +## BW2 = erosion(BW1, SE) returns a binary image with the result of an erosion +## operation on @var{BW1} using neighbour mask @var{SE}. +## +## For each point in @var{BW1}, erode searchs its neighbours (which are +## defined by setting to 1 their in @var{SE}). If all neighbours +## are on (1), then pixel is set to 1. If any is off (0) then it is set to 0. +## +## Center of @var{SE} is calculated using floor((size(@var{SE})+1)/2). +## +## Pixels outside the image are considered to be 0. +## +## BW2 = erode(BW1, SE, alg) returns the result of a erosion operation +## using algorithm @var{alg}. Only 'spatial' is implemented at the moment. +## +## BW2 = erosion(BW1, SE, ..., n) returns the result of @var{n} erosion +## operations on @var{BW1}. +## +## @end deftypefn +## @seealso{dilate} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function BW2 = erode(BW1, SE, a, b) + alg='spatial'; + n=1; + if (nargin < 1 || nargin > 4) + usage ("BW2 = erode(BW1, SE [, alg] [, n])"); + endif + if nargin == 4 + alg=a; + n=b; + elseif nargin == 3 + if ischar(a) + alg=a; + else + n=a; + endif + endif + + if !strcmp(alg, 'spatial') + error("erode: alg not implemented."); + endif + + # count ones in mask + thr=sum(SE(:)); + + # "Binarize" BW1, just in case image is not [1,0] + BW1=BW1!=0; + + for i=1:n + # create result matrix + BW1=filter2(SE,BW1) == thr; + endfor + + BW2=BW1; +endfunction + +%!demo +%! erode(ones(5,5),ones(3,3)) +%! % creates a zeros border around ones. + + + +%!assert(erode([0,1,0;1,1,1;0,1,0],[0,0,0;0,0,1;0,1,1])==[1,0,0;0,0,0;0,0,0]); +%!assert(erode([0,1,0;1,1,1;0,1,0],[0,1;1,1])==[1,0,0;0,0,0;0,0,0]); + +
new file mode 100644 --- /dev/null +++ b/inst/fftconv2.m @@ -0,0 +1,134 @@ +## Copyright (C) 2004 Stefan van der Walt <stefan@sun.ac.za> +## +## This program is free software; redistribution and use in source and +## binary forms, with or without modification, are permitted provided that +## the following conditions are met: +## +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +## OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +## SUCH DAMAGE. + +## FFTCONV2 Convolve 2 dimensional signals using the FFT. +## +## usage: fftconv2(a, b[, shape]) +## fftconv2(v1, v2, a, shape) +## +## This method is faster but less accurate for large a,b. It +## also uses more memory. A small complex component will be +## introduced even if both a and b are real. +## +## see also: conv2 + +## Author: Stefan van der Walt <stefan@sun.ac.za> +## Date: 2004 + +function X = fftconv2(varargin) + if (nargin < 2) + usage("fftconv2(a,b[,shape]) or fftconv2(v1, v2, a, shape)") + endif + + shape = "full"; + rowcolumn = 0; + + if ((nargin > 2) && ismatrix(varargin{3})) + ## usage: fftconv2(v1, v2, a[, shape]) + + rowcolumn = 1; + v1 = varargin{1}(:)'; + v2 = varargin{2}(:); + orig_a = varargin{3}; + + if (nargin == 4) shape = varargin{4}; endif + else + ## usage: fftconv2(a, b[, shape]) + + a = varargin{1}; + b = varargin{2}; + if (nargin == 3) shape = varargin{3}; endif + + endif + + if (rowcolumn) + a = fftconv2(orig_a, v2); + b = v1; + endif + + ra = rows(a); + ca = columns(a); + rb = rows(b); + cb = columns(b); + + A = fft2(impad(a, [0 cb-1], [0 rb-1])); + B = fft2(impad(b, [0 ca-1], [0 ra-1])); + + X = ifft2(A.*B); + + if (rowcolumn) + rb = rows(v2); + ra = rows(orig_a); + cb = columns(v1); + ca = columns(orig_a); + endif + + if strcmp(shape,"same") + r_top = ceil((rb + 1) / 2); + c_top = ceil((cb + 1) / 2); + X = X(r_top:r_top + ra - 1, c_top:c_top + ca - 1); + elseif strcmp(shape, "valid") + X = X(rb:ra, cb:ca); + endif +endfunction + +%!# usage: fftconv2(a,b,[, shape]) +%!shared a,b +%! a = repmat(1:10, 5); +%! b = repmat(10:-1:3, 7); +%!assert(norm(fftconv2(a,b)-conv2(a,b)), 0, 1e6*eps) +%!assert(norm(fftconv2(b,a)-conv2(b,a)), 0, 1e6*eps) +%!assert(norm(fftconv2(a,b,'full')-conv2(a,b,'full')), 0, 1e6*eps) +%!assert(norm(fftconv2(b,a,'full')-conv2(b,a,'full')), 0, 1e6*eps) +%!assert(norm(fftconv2(a,b,'same')-conv2(a,b,'same')), 0, 1e6*eps) +%!assert(norm(fftconv2(b,a,'same')-conv2(b,a,'same')), 0, 1e6*eps) +%!assert(isempty(fftconv2(a,b,'valid'))); +%!assert(norm(fftconv2(b,a,'valid')-conv2(b,a,'valid')), 0, 1e6*eps) + +%!# usage: fftconv2(v1, v2, a[, shape]) +%!shared x,y,a +%! x = 1:4; y = 4:-1:1; a = repmat(1:10, 5); +%!assert(norm(fftconv2(x,y,a)-conv2(x,y,a)), 0, 1e6*eps) +%!assert(norm(fftconv2(x,y,a,'full')-conv2(x,y,a,'full')), 0, 1e6*eps) +%!assert(norm(fftconv2(x,y,a,'same')-conv2(x,y,a,'same')), 0, 1e6*eps) +%!assert(norm(fftconv2(x,y,a,'valid')-conv2(x,y,a,'valid')), 0, 1e6*eps) + +%!demo +%! ## Draw a cross +%! N = 100; +%! [x,y] = meshgrid(-N:N, -N:N); +%! z = 0*x; +%! z(N,1:2*N+1) = 1; z(1:2*N+1, N) = 1; +%! imshow(z); +%! +%! ## Draw a sinc blob +%! n = floor(N/10); +%! [x,y] = meshgrid(-n:n, -n:n); +%! b = x.^2 + y.^2; b = max(b(:)) - b; b = b / max(b(:)); +%! imshow(b); +%! +%! ## Convolve the cross with the blob +%! imshow(real(fftconv2(z, b, 'same')*N)) + +
new file mode 100644 --- /dev/null +++ b/inst/flag.m @@ -0,0 +1,50 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} flag (@var{n}) +## Create color colormap. +## (cycling through red, white, blue and black) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +## flag(number) gives a colormap consists of red, white, blue and black +## changing with each index + +function map = flag (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("flag: argument must be a scalar"); + endif + else + usage ("flag (number)"); + endif + + p = [1, 0, 0; 1, 1, 1; 0, 0, 1; 0, 0, 0]; + if (rem(number,4) == 0) + map=kron (ones (number / 4, 1), p); + else + map=[kron(ones (fix (number / 4), 1), p); p(1:rem (number, 4), :)]; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/grayslice.m @@ -0,0 +1,78 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{X} =} grayslice (@var{I},@var{n}) +## @deftypefnx {Function File} {@var{X} =} grayslice (@var{I},@var{v}) +## creates an indexed image @var{X} from an intensitiy image @var{I} +## using multiple threshold levels. +## A scalar integer value @var{n} sets the levels to +## @example +## +## @group +## 1 2 n-1 +## -, -, ..., --- +## n n n +## @end group +## @end example +## +## X = grayslice(I,5); +## +## For irregular threshold values a real vector @var{v} can be used. +## The values must be in the range [0,1]. +## +## @group +## X = grayslice(I,[0.1,0.33,0.75,0.9]) +## @end group +## +## @end deftypefn +## @seealso{im2bw} + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 03. August 2000 + +function X = grayslice (I, v) + + if (nargin != 2) + usage ("grayslice(...) number of arguments must be 1 or 2"); + endif + + if (is_scalar(v) && (fix(v) == v)) + + v = (1:v - 1) / v; + + elseif (isvector(v)) + + if (any (v < 0) || (any (v > 1))) + error ("slice vector must be in range [0,1]") + endif + v = [0,v,1]; + else + + usage("second argument"); + + endif + + [r, c] = size (I); + [m, n] = sort ([v(:); I(:)]); + lx = length (v); + o = cumsum (n <= lx); + idx = o (find(n>lx)); + [m, n] = sort (I(:)); + [m, n] = sort (n); + X = reshape (idx(n), r, c); + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/histeq.m @@ -0,0 +1,33 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{J}= histeq (@var{I},@var{n}) +## histogram equalization +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 08. August 2000 + +function J = histeq (I, n) + + [r,c] = size (I); + [X,map] = gray2ind(I); + [nn,xx] = imhist(I); + Icdf = ceil (n * cumsum (1/prod(size(I)) * nn)); + J = reshape(Icdf(X),r,c); + plot(Icdf,'b;;'); +endfunction
new file mode 100644 --- /dev/null +++ b/inst/hot.m @@ -0,0 +1,52 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} hot (@var{n}) +## Create color colormap. +## (black through dark red, red, orange, yellow to white) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = hot (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("hot: argument must be a scalar"); + endif + else + usage ("hot (number)"); + endif + + if (number == 1) + map = [0, 0, 0]; + elseif (number > 1) + x = linspace (0, 1, number)'; + r = (x < 2/5) .* (5/2 * x) + (x >= 2/5); + g = (x >= 2/5 & x < 4/5) .* (5/2 * x - 1) + (x >= 4/5); + b = (x >= 4/5) .* (5*x - 4); + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/hsv.m @@ -0,0 +1,49 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} hsv (@var{n}) +## Create color colormap. +## (red through yellow, green, cyan,blue,magenta to red) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = hsv (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("hsv: argument must be a scalar"); + endif + else + usage ("hsv (number)"); + endif + + if (number == 1) + map = [1, 0, 0]; + elseif (number > 1) + h = linspace (0, 1, number)'; + map = hsv2rgb ([h, ones(number, 1), ones(number, 1)]); + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/im2bw.m @@ -0,0 +1,50 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{BW}= im2bw (@var{I},threshold) +## @deftypefnx {Function File} @var{BW}= im2bw (@var{X},@var{cmap},threshold) +## converts image data types to a black-white (binary) image. +## The treshold value should be in the range [0,1]. +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 19. March 2000 + +function BW = im2bw (img, a, b) + + if ( nargin < 2 || nargin > 3) + usage("im2bw(I) number of arguments must be 2 or 3"); + endif + + if (isgray (img)) + if (is_scalar (a)) + BW = (img >= a); + else + error ("threshold value must be scalar"); + endif + elseif (isind (img)) + if (is_matrix (a) && columns (a) == 3) + if (is_scalar (b)) + I = ind2gray (img, a); + BW = (I >= b); + endif + endif + else + error ("image matrix must be of index or intensity type"); + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/im2col.m @@ -0,0 +1,255 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{B} = } im2col (@var{A}, [@var{m},@var{n}], @var{block_type}) +## @deftypefnx {Function File} {@var{B} = } im2col (@var{A}, [@var{m},@var{n}]) +## @deftypefnx {Function File} {@var{B} = } im2col (@var{A}, 'indexed', ...) +## Rearranges image blocks into columns +## +## @code{B=im2col(A, [m, n], blocktype)} rearranges blocks in @var{A} +## into columns in a way that's determined by @var{block_type}, which +## can take the following values: +## +## @table @code +## @item distinct +## Rearranges each distinct @var{m}-by-@var{n} block in image @var{A} +## into a column of @var{B}. Blocks are scanned from left to right and +## the up to bottom in @var{A}, and columns are added to @var{B} from +## left to right. If @var{A}'s size is not multiple @var{m}-by-@var{n} +## it is padded. +## @item sliding +## Rearranges any @var{m}-by-@var{n} sliding block of @var{A} in a +## column of @var{B}, without any padding, so only sliding blocks which +## can be built using a full @var{m}-by-@var{n} neighbourhood are taken. +## In consequence, @var{B} has @var{m}*@var{n} rows and +## (@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1) columns (where @var{mm} and +## @var{nn} are the size of @var{A}). +## +## This case is thought to be used applying operations on columns of +## @var{B} (for instance using sum(:)), so that result is a +## 1-by-(@var{mm}-@var{m}+1)*(@var{nn}-@var{n}+1) vector, that is what +## the complementary function @code{col2im} expects. +## @end table +## +## @code{B=im2col(A,[m,n])} takes @code{distinct} as a default value for +## @var{block_type}. +## +## @code{B=im2col(A,'indexed',...)} will treat @var{A} as an indexed +## image, so it will pad using 1 if @var{A} is double. All other cases +## (incluing indexed matrices with uint8 and uint16 types and +## non-indexed images) will use 0 as padding value. +## +## Any padding needed in 'distinct' processing will be added at right +## and bottom edges of the image. +## +## @strong{Compatibility notes:} +## +## @itemize @bullet +## @item +## 'sliding' blocks are arranged into @var{B} in a top-down and +## left-right order. Since this isn't explicity described in MATLAB +## documentation, we ignore if it does it this way. It has been +## deduced because im2col implements inverse operation as a simple +## reshape (if we chose left to right and then up to down order we would +## had to transpose result). If you have MATLAB please check this +## issue. +## @item +## MATLAB docs say that when using @code{'indexed'}, padding with 0 is +## done for uint8 type. Since most functions do that too for uint16, we +## have chosen to use 0 also for uint16, even if documentation doesn't +## say it explicity, since it looks as an omission. +## @end itemize +## +## @end deftypefn +## @seealso{col2im} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function B = im2col(A, varargin) + if(nargin<2 || nargin>4) + usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); + endif + + ## check 'indexed' presence + indexed=false; + p=1; + if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) + if(nargin<3) + usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); + endif + indexed=true; + p+=1; + if(isa(A,"uint8") || isa(A,"uint16")) + padval=0; + else + padval=1; + endif + else + padval=0; + endif + + ## check [m,n] + if(!isvector(varargin{p})) + error("im2col: expected [m,n] but param is not a vector."); + endif + if(length(varargin{p})!=2) + error("im2col: expected [m,n] but param has wrong length."); + endif + m=varargin{p}(1); + n=varargin{p}(2); + p+=1; + + block_type='sliding'; + if(nargin>p) + ## we have block_type param + if(!ischar(varargin{p})) + error("im2col: invalid parameter block_type."); + endif + block_type=varargin{p}; + p+=1; + endif + + ## if we didn't have 'indexed' but had 4 parameters there's an error + if(nargin>p) + usage("B=im2col(B [, 'indexed'], [m,n] [, block_type])"); + endif + + + ## common checks + if(!ismatrix(A)) + error("im2col: A should be a matrix (or vector)."); + endif + + switch(block_type) + case('distinct') + ## calc needed padding + sp=mod(-size(A)',[m;n]); + + if(any(sp)) + A=padarray(A,sp,padval,'post'); + endif + + ## iterate through all blocks + B=[]; + for i=1:m:size(A,1) ## up to bottom + for j=1:n:size(A,2) ## left to right + ## TODO: check if we can horzcat([],uint8([10;11])) in a + ## future Octave version > 2.1.58 + if(isempty(B)) + B=A(i:i+m-1,j:j+n-1)(:); + else + B=horzcat(B, A(i:i+m-1,j:j+n-1)(:)); + endif + endfor + endfor + + case('sliding') + if(indexed) + disp("WARNING: 'indexed' has no sense when using sliding."); + endif + if(m>size(A,1) || n>size(A,2)) + error("im2col: block size can't be greater than image size in sliding"); + endif + ## TODO: check if matlab uses top-down and left-right order + B=[]; + for j=1:1:size(A,2)-n+1 ## left to right + for i=1:1:size(A,1)-m+1 ## up to bottom + ## TODO: check if we can horzcat([],uint8([10;11])) in a + ## future Octave version > 2.1.58 + if(isempty(B)) + B=A(i:i+m-1,j:j+n-1)(:); + else + B=horzcat(B, A(i:i+m-1,j:j+n-1)(:)); + endif + endfor + endfor + + otherwise + error("im2col: invalid block_type."); + endswitch + +endfunction + +%!demo +%! A=[1:10;11:20;21:30;31:40] +%! B=im2col(A,[2,5],'distinct') +%! C=col2im(B,[2,5],[4,10],'distinct') +%! # Divide A using distinct blocks and reverse operation + +%!shared B, A, Bs, As, Ap, Bp0, Bp1 +%! v=[1:10]'; +%! r=reshape(v,2,5); +%! B=[v, v+10, v+20, v+30, v+40, v+50]; +%! A=[r, r+10; r+20, r+30; r+40, r+50]; +%! As=[1,2,3,4,5;6,7,8,9,10;11,12,13,14,15]; +%! b1=As(1:2,1:4)(:); +%! b2=As(2:3,1:4)(:); +%! b3=As(1:2,2:5)(:); +%! b4=As(2:3,2:5)(:); +%! Bs=[b1,b2,b3,b4]; +%! Ap=A(:,1:9); +%! Bp1=Bp0=B; +%! Bp0([9:10],[2,4,6])=0; +%! Bp1([9:10],[2,4,6])=1; + +%!# bad block_type +%!error(im2col(A,[2,5],'wrong_block_type')); + +%!# distinct +%!assert(im2col(A,[2,5],'distinct'), B); + +%!# padding +%!assert(im2col(Ap,[2,5],'distinct'), Bp0); +%!assert(im2col(Ap,'indexed',[2,5],'distinct'), Bp1); + +%!# now sliding +%!assert(im2col(As,[2,4]), Bs); +%!assert(im2col(As,[2,4],'sliding'), Bs); +%!assert(im2col(As,[3,5],'sliding'), As(:)); + +%!# disctint uint8 & uint16 +%!assert(im2col(uint8(A),[2,5],'distinct'), uint8(B)); +%!assert(im2col(uint16(A),[2,5],'distinct'), uint16(B)); + +%!# padding uint8 & uint16 (to 0 even in indexed case) +%!assert(im2col(uint8(Ap),[2,5],'distinct'), uint8(Bp0)); +%!assert(im2col(uint8(Ap),'indexed',[2,5],'distinct'), uint8(Bp0)); +%!assert(im2col(uint16(Ap),[2,5],'distinct'), uint16(Bp0)); +%!assert(im2col(uint16(Ap),'indexed',[2,5],'distinct'), uint16(Bp0)); + +%!# now sliding uint8 & uint16 +%!assert(im2col(uint8(As),[2,4],'sliding'), uint8(Bs)); +%!assert(im2col(uint16(As),[2,4],'sliding'), uint16(Bs)); + + + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:33 hauberg +% Changed the structure to match the package system +% +% Revision 1.3 2005/09/08 02:00:17 pkienzle +% [for Bill Denney] isstr -> ischar +% +% Revision 1.2 2004/09/03 17:37:08 jmones +% Added support for int* and uint* types +% +% Revision 1.1 2004/08/18 14:39:07 jmones +% im2col and col2im added +% +%
new file mode 100644 --- /dev/null +++ b/inst/imadjust.m @@ -0,0 +1,356 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +## +## +## Based on old imadjust.m (GPL): +## Copyright (C) 1999,2000 Kai Habel + + +## -*- texinfo -*- +## @deftypefn {Function File} @var{J}= imadjust (@var{I}) +## @deftypefnx {Function File} @var{J}= imadjust (@var{I},[@var{low_in};@var{high_in}]) +## @deftypefnx {Function File} @var{J}= imadjust (@var{I},[@var{low_in};@var{high_in}],[@var{low_out};@var{high_out}]) +## @deftypefnx {Function File} @var{J}= imadjust (..., @var{gamma}) +## @deftypefnx {Function File} @var{newmap}= imadjust (@var{map}, ...) +## @deftypefnx {Function File} @var{RGB_out}= imadjust (@var{RGB}, ...) +## Adjust image or colormap values to a specified range +## +## @code{J=imadjust(I)} adjusts intensity image @var{I} values so that +## 1% of data on lower and higher values (2% in total) of the image is +## saturated; choosing for that the corresponding lower and higher +## bounds (using @code{stretchlim}) and mapping them to 0 and 1. @var{J} +## is an image of the same size as @var{I} which contains mapped values. +## This is equivalent to @code{imadjust(I,stretchlim(I))}. +## +## @code{J=imadjust(I,[low_in;high_in])} behaves as described but uses +## @var{low_in} and @var{high_in} values instead of calculating them. It +## maps those values to 0 and 1; saturates values lower than first limit +## to 0 and values higher than second to 1; and finally maps all values +## between limits linearly to a value between 0 and 1. If @code{[]} is +## passes as @code{[low_in;high_in]} value, then @code{[0;1]} is taken +## as a default value. +## +## @code{J=imadjust(I,[low_in;high_in],[low_out;high_out])} behaves as +## described but maps output values between @var{low_out} and +## @var{high_out} instead of 0 and 1. A default value @code{[]} can also +## be used for this parameter, which is taken as @code{[0;1]}. +## +## @code{J=imadjust(...,gamma)} takes, in addition of 3 parameters +## explained above, an extra parameter @var{gamma}, which specifies the +## shape of the mapping curve between input elements and output +## elements, which is linear (as taken if this parameter is omitted). If +## @var{gamma} is above 1, then function is weighted towards lower +## values, and if below 1, towards higher values. +## +## @code{newmap=imadjust(map,...)} applies a transformation to a +## colormap @var{map}, which output is @var{newmap}. This transformation +## is the same as explained above, just using a map instead of an image. +## @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and +## @var{gamma} can be scalars, in which case the same values are applied +## for all three color components of a map; or it can be 1-by-3 +## vectors, to define unique mappings for each component. +## +## @code{RGB_out=imadjust(RGB,...)} adjust RGB image @var{RGB} (a +## M-by-N-by-3 array) the same way as specified in images and colormaps. +## Here too @var{low_in}, @var{high_in}, @var{low_out}, @var{high_out} and +## @var{gamma} can be scalars or 1-by-3 matrices, to specify the same +## mapping for all planes, or unique mappings for each. +## +## The formula used to realize the mapping (if we omit saturation) is: +## +## @code{J = low_out + (high_out - low_out) .* ((I - low_in) / (high_in - low_in)) .^ gamma;} +## +## @strong{Compatibility notes:} +## +## @itemize @bullet +## @item +## Prior versions of imadjust allowed @code{[low_in; high_in]} and +## @code{[low_out; high_out]} to be row vectors. Compatibility with this +## behaviour has been keeped, although preferred form is vertical vector +## (since it extends nicely to 2-by-3 matrices for RGB images and +## colormaps). +## @item +## Previous version of imadjust, if @code{low_in>high_in} it "negated" output. +## Now it is negated if @code{low_out>high_out}, for compatibility with +## MATLAB. +## @item +## Class of @var{I} is not considered, so limit values are not +## modified depending on class of the image, just treated "as is". When +## Octave 2.1.58 is out, limits will be multiplied by 255 for uint8 +## images and by 65535 for uint16 as in MATLAB. +## @end itemize +## +## @end deftypefn +## @seealso{stretchlim, brighten} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +## TODO: When Octave 2.1.58 is out multiply indices if input argument is +## TODO: of class int* or uint*. + +function ret = imadjust (image, in, out, gamma) + + if (nargin < 1 || nargin > 4) + usage ("imadjust(...) number of arguments must be between 1 and 4"); + endif + + if (nargin < 4) + gamma = 1; ## default gamma + endif + + if !(ismatrix(image)) + error ("imadjust(image,...) first parameter must be a image matrix or colormap"); + endif + + if (nargin==1) + in=stretchlim(image); ## this saturates 1% on lower and 1% on + out=[0;1]; ## higher values + endif + + if (nargin==2) + out=[0;1]; ## default out + endif + + if !((ismatrix(in) || isempty(in)) && (ismatrix(out) || isempty(out)) ) + usage("imadjust(image,[low high],[bottom top],gamma)"); + endif + + if (isempty(in)) + in=[0;1]; ## default in + endif + + if (isempty(out)) + out=[0;1]; ## default out + endif + + simage=size(image); + if (length(simage)==3 && simage(3)==3) + ## image is rgb + [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); + + ## make room + ret=zeros(size(image)); + + ## process each plane + for i=1:3 + ret(:,:,i)=__imadjust_plane__(image(:,:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(1,i)); + endfor + + elseif (length(simage)==2) + if(simage(2)==3 && \ + (size(in)==[2,3] || size(out)==[2,3] || size(gamma)==[1,3]) ) + ## image is a colormap + [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma); + + ret=[]; + ## process each color + for i=1:3 + ret=horzcat(ret,__imadjust_plane__(image(:,i),in(1,i),in(2,i),out(1,i),out(2,i),gamma(i))); + endfor + + else + ## image is a intensity image + if( !isvector(in) || length(in)!=2 || !isvector(out) || length(out)!=2 || !isscalar(gamma) || (gamma<0) || (gamma==Inf) ) + error("imadjust: on an intensity image, in and out must be 2-by-1 and gamma a positive scalar."); + endif + ret=__imadjust_plane__(image,in(1),in(2),out(1),out(2),gamma); + endif + + else + error("imadjust: first parameter must be a colormap, an intensity image or a RGB image"); + endif +endfunction + + +## This does all the work. I has a plane; li and hi input low and high +## values; and lo and ho, output bottom and top values. +## Image negative is computed if ho<lo although nothing special is +## needed, since formula automatically handles it. +function ret=__imadjust_plane__(I, li, hi, lo, ho, gamma) + ret = (I < li) .* lo; + ret = ret + (I >= li & I < hi) .* (lo + (ho - lo) .* ((I - li) / (hi - li)) .^ gamma); + ret = ret + (I >= hi) .* ho; +endfunction + + +## Checks in, out and gamma to see if they are ok for colormap and RGB +## cases. +function [in, out, gamma]=__imadjust_check_3d_args__(in, out, gamma) + switch(size(in)) + case([2,3]) + ## ok! + case([2,1]) + in=repmat(in,1,3); + case([1,2]) ## Compatibility behaviour! + in=repmat(in',1,3); + otherwise + error("imadjust: in must be 2-by-3 or 2-by-1."); + endswitch + + switch(size(out)) + case([2,3]) + ## ok! + case([2,1]) + out=repmat(out,1,3); + case([1,2]) ## Compatibility behaviour! + out=repmat(out',1,3); + otherwise + error("imadjust: out must be 2-by-3 or 2-by-1."); + endswitch + + switch(size(gamma)) + case([1,3]) + ## ok! + case([1,1]) + gamma=repmat(gamma,1,3); + otherwise + error("imadjust: gamma must be a scalar or a 1-by-3 matrix."); + endswitch + + ## check gamma allowed range + if(!all((gamma>=0)&(gamma<Inf))) + error("imadjust: gamma values must be in the range [0,Inf]"); + endif + +endfunction + + +# bad arguments + +# bad images +%!error(imadjust("bad argument")); +%!error(imadjust(zeros(10,10,3,2))); +%!error(imadjust(zeros(10,10,4))); +%!error(imadjust("bad argument")); + +# bad 2d, 3d or 4th argument +%!error(imadjust([1:100],"bad argument",[0;1],1)); +%!error(imadjust([1:100],[0,1,1],[0;1],1)); +%!error(imadjust([1:100],[0;1],[0,1,1],1)); +%!error(imadjust([1:100],[0;1],[0;1],[0;1])); +%!error(imadjust([1:100],[0;1],[0;1],-1)); + +%!# 1% on each end saturated +%!assert(imadjust([1:100]),[0,linspace(0,1,98),1]); + +%!# test with only input arg +%!assert(sum(abs((imadjust(linspace(0,1,100),[1/99;98/99]) - \ +%! [0,linspace(0,1,98),1] )(:))) < 1e-10); + +%!# a test with input and output args +%!assert(imadjust([1:100],[50;90],[-50;-30]), \ +%! [-50*ones(1,49), linspace(-50,-30,90-50+1), -30*ones(1,10)]); + +%!# a test with input and output args in a row vector (Compatibility behaviour) +%!assert(imadjust([1:100],[50,90],[-50,-30]), \ +%! [-50*ones(1,49), linspace(-50,-30,90-50+1), -30*ones(1,10)]); + +%!# the previous test, "negated" +%!assert(imadjust([1:100],[50;90],[-30;-50]), \ +%! [-30*ones(1,49), linspace(-30,-50,90-50+1), -50*ones(1,10)]); + + +%!shared cm,cmn +%! cm=[[1:10]',[2:11]',[3:12]']; +%! cmn=([[1:10]',[2:11]',[3:12]']-1)/11; + +%!# a colormap +%!assert(imadjust(cmn,[0;1],[10;11]),cmn+10); + +%!# a colormap with params in row (Compatibility behaviour) +%!assert(imadjust(cmn,[0,1],[10,11]),cmn+10); + +%!# a colormap, different output on each +%!assert(imadjust(cmn,[0;1],[10,20,30;11,21,31]),cmn+repmat([10,20,30],10,1)); + +%!# a colormap, different input on each, we need increased tolerance for this test +%!assert(sum(abs((imadjust(cm,[2,4,6;7,9,11],[0;1]) - \ +%! [[0,linspace(0,1,6),1,1,1]', \ +%! [0,0,linspace(0,1,6),1,1]', \ +%! [0,0,0,linspace(0,1,6),1]'] \ +%! ))(:)) < 1e-10 \ +%! ); + +%!# a colormap, different input and output on each +%!assert(sum(abs((imadjust(cm,[2,4,6;7,9,11],[0,1,2;1,2,3]) - \ +%! [[0,linspace(0,1,6),1,1,1]', \ +%! [0,0,linspace(0,1,6),1,1]'+1, \ +%! [0,0,0,linspace(0,1,6),1]'+2] \ +%! ))(:)) < 1e-10 \ +%! ); + +%!# a colormap, different gamma, input and output on each +%!assert(sum(abs((imadjust(cm,[2,4,6;7,9,11],[0,1,2;1,2,3],[1,2,3]) - \ +%! [[0,linspace(0,1,6),1,1,1]', \ +%! [0,0,linspace(0,1,6).^2,1,1]'+1, \ +%! [0,0,0,linspace(0,1,6).^3,1]'+2] \ +%! )(:))) < 1e-10 \ +%! ); + + +%!shared iRGB,iRGBn,oRGB +%! iRGB=zeros(10,1,3); +%! iRGB(:,:,1)=[1:10]'; +%! iRGB(:,:,2)=[2:11]'; +%! iRGB(:,:,3)=[3:12]'; +%! iRGBn=(iRGB-1)/11; +%! oRGB=zeros(10,1,3); +%! oRGB(:,:,1)=[0,linspace(0,1,6),1,1,1]'; +%! oRGB(:,:,2)=[0,0,linspace(0,1,6),1,1]'; +%! oRGB(:,:,3)=[0,0,0,linspace(0,1,6),1]'; + +%!# a RGB image +%!assert(imadjust(iRGBn,[0;1],[10;11]),iRGBn+10); + +%!# a RGB image, params in row (compatibility behaviour) +%!assert(imadjust(iRGBn,[0,1],[10,11]),iRGBn+10); + +%!# a RGB, different output on each +%!test +%! t=iRGBn; +%! t(:,:,1)+=10; +%! t(:,:,2)+=20; +%! t(:,:,3)+=30; +%! assert(imadjust(iRGBn,[0;1],[10,20,30;11,21,31]),t); + + +%!# a RGB, different input on each, we need increased tolerance for this test +%!assert(sum(abs((imadjust(iRGB,[2,4,6;7,9,11],[0;1]) - oRGB)(:))) < 1e-10); + +%!# a RGB, different input and output on each +%!test +%! t=oRGB; +%! t(:,:,2)+=1; +%! t(:,:,3)+=2; +%! assert(sum(abs((imadjust(iRGB,[2,4,6;7,9,11],[0,1,2;1,2,3]) - t)(:))) < 1e-10); + +%!# a RGB, different gamma, input and output on each +%!test +%! t=oRGB; +%! t(:,:,2)=t(:,:,2).^2+1; +%! t(:,:,3)=t(:,:,3).^3+2; +%! assert(sum(abs((imadjust(iRGB,[2,4,6;7,9,11],[0,1,2;1,2,3],[1,2,3]) - t)(:))) < 1e-10); + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:33 hauberg +% Changed the structure to match the package system +% +% Revision 1.3 2004/09/01 22:51:14 jmones +% Fully recoded: NDArray support, docs, tests, more compatible with MATLAB, changed copyright +% +%
new file mode 100644 --- /dev/null +++ b/inst/imginfo.m @@ -0,0 +1,52 @@ +## Copyright (C) 2002 Etienne Grossmann. All rights reserved. +## +## This program is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## This is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +## for more details. +## + +## [h,w] = imginfo (filename) - Get image size from file +## hw = imginfo (filename) +## +## filename : string : Name of image file +## +## h : 1 : Height of image, in pixels +## w : 1 : Width of image, in pixels +## or +## hw=[h,w] : 2 : Height and width of image +## +## NOTE : imginfo relies on the 'convert' program. + +## Author: Etienne Grossmann <etienne@cs.uky.edu> +## Last modified: Setembro 2002 + +function [h,w] = imginfo (fn) + +[status, res] = system(sprintf("convert -verbose '%s' /dev/null",fn),1); + +if status, + error (["imginfo : 'convert' exited with status %i ",\ + "and produced\n%s\n"],\ + status, res); +end + +res = res(index(res," ")+1:length(res)); + +i = index (res,"x"); +if ! i, error ("imginfo : Can't interpret string (i)\n%s\n", res); end + +j = index (res(i-1:-1:1)," "); +if j<2, error ("imginfo : Can't interpret string (j)\n%s\n", res); end +w = str2num (res(i-j:i-1)); + +k = index (res(i+1:length(res))," "); +if k<2, error ("imginfo : Can't interpret string (k)\n%s\n", res); end +h = str2num (res(i+1:i+k)); + +if nargout<2, h = [h,w]; end
new file mode 100644 --- /dev/null +++ b/inst/imhist.m @@ -0,0 +1,72 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} imhist (@var{I},@var{n}) +## @deftypefnx {Function File} {} imhist (@var{I}) +## @deftypefnx {Function File} {} imhist (@var{X},@var{cmap}) +## @deftypefnx {Function File} {[@var{n,x}] = } imhist (...) +## Shows the histogram of an image using hist +## @end deftypefn +## @seealso{hist} + +## Author: Kai Habel <kai.habel@gmx.de> +## July 2000 : Paul Kienzle code simplification for hist() call. + +function [varargout] = imhist (I, b) + + if (nargin < 1 || nargin > 2) + usage("imhist(image,n)"); + endif + + b_is_colormap = 0; + + if (nargin == 2) + if (is_matrix (b)) + b_is_colormap = (columns (b) == 3); + endif + endif + + if (b_is_colormap) + ## assuming I is an indexed image + ## b is colormap + max_idx = max (max (I)); + bins = rows (b); + if (max_idx > bins) + warning ("largest index exceedes length of colormap"); + endif + else + ## assuming I is an intensity image + ## b is number of bins + if (nargin == 1) + bins = 256; + else + bins = b; + endif + + ## scale image to range [0,1] + I = mat2gray (I); + endif + + if (nargout == 2) + [nn,xx] = hist (I(:), bins); + vr_val_cnt = 1; varargout{vr_val_cnt++} = nn; + varargout{vr_val_cnt++} = xx; + else + hist (I(:), bins); + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imnoise.m @@ -0,0 +1,72 @@ +## Copyright (C) 2000 Paul Kienzle +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## usage: B = imnoise (A, type) +## +## Adds noise to image in A. +## +## imnoise (A, 'gaussian' [, mean [, var]]) +## additive gaussian noise: A = A + noise +## defaults to mean=0, var=0.01 +## +## imnoise (A, 'salt & pepper' [, density]) +## lost pixels: A = 0 or 1 for density*100% of the pixels +## defaults to density=0.05, or 5% +## +## imnoise (A, 'speckle' [, var]) +## multiplicative gaussian noise: A = A + A*noise +## defaults to var=0.04 + +## Modified: Stefan van der Walt <stefan@sun.ac.za>, 2004-02-24 + +function A = imnoise(A, stype, a, b) + + if (nargin < 2 || nargin > 4 || !is_matrix(A) || !ischar(stype)) + usage("B = imnoise(A, type, parameters, ...)"); + endif + + valid = (min(A(:)) >= 0 && max(A(:)) <= 1); + + stype = tolower(stype); + if (strcmp(stype, 'gaussian')) + if (nargin < 3), a = 0.0; endif + if (nargin < 4), b = 0.01; endif + A = A + (a + randn(size(A)) * sqrt(b)); + ## Variance of Gaussian data with mean 0 is E[X^2] + elseif (strcmp(stype, 'salt & pepper')) + if (nargin < 3), a = 0.05; endif + noise = rand(size(A)); + A(noise <= a/2) = 0; + A(noise >= 1-a/2) = 1; + elseif (strcmp(stype, 'speckle')) + if (nargin < 3), a = 0.04; endif + A = A .* (1 + randn(size(A))*sqrt(a)); + else + error("imnoise: use type 'gaussian', 'salt & pepper', or 'speckle'"); + endif + + if valid + A(A>1) = 1; + A(A<0) = 0; + else + warning("Image should be in [0,1]"); + endif + +endfunction + +%!assert(var(imnoise(ones(10)/2,'gaussian')(:)),0.01,0.005) # probabilistic +%!assert(length(find(imnoise(ones(10)/2,'salt & pepper')~=0.5)),5,10) # probabilistic +%!assert(var(imnoise(ones(10)/2,'speckle')(:)),0.01,0.005) # probabilistic
new file mode 100644 --- /dev/null +++ b/inst/impad.m @@ -0,0 +1,142 @@ +## Copyright (C) 2000 Teemu Ikonen +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +## -*- texinfo -*- +## @deftypefn {Function File} {} impad(@var{A}, @var{xpad}, @var{ypad}, [@var{padding}, [@var{const}]]) +## Pad (augment) a matrix for application of image processing algorithms. +## +## Pads the input image @var{A} with @var{xpad}(1) elements from left, +## @var{xpad}(2), elements from right, @var{ypad}(1) elements from above +## and @var{ypad}(2) elements from below. +## Values of padding elements are determined from the optional arguments +## @var{padding} and @var{const}. @var{padding} is one of +## +## @table @samp +## @item "zeros" +## pad with zeros (default) +## +## @item "ones" +## pad with ones +## +## @item "constant" +## pad with a value obtained from the optional fifth argument const +## +## @item "symmetric" +## pad with values obtained from @var{A} so that the padded image mirrors +## @var{A} starting from edges of @var{A} +## +## @item "reflect" +## same as symmetric, but the edge rows and columns are not used in the padding +## +## @item "replicate" +## pad with values obtained from A so that the padded image +## repeates itself in two dimensions +## +## @end table +## @end deftypefn + +## Author: Teemu Ikonen <tpikonen@pcu.helsinki.fi> +## Created: 5.5.2000 +## Keywords: padding image processing + +## A nice test matrix for padding: +## A = 10*[1:5]' * ones(1,5) + ones(5,1)*[1:5] + +function retval = impad(A, xpad, ypad, padding, const) + +try empty_list_elements_ok_save = empty_list_elements_ok; +catch empty_list_elements_ok_save = 0; +end +try warn_empty_list_elements_save = warn_empty_list_elements; +catch warn_empty_list_elements_save = 0; +end +unwind_protect + +if nargin < 4, padding = "zeros"; endif +if nargin < 5, const = 1; endif +if isscalar(xpad), xpad(2) = xpad(1); endif +if isscalar(ypad), ypad(2) = ypad(1); endif + +origx = size(A,2); +origy = size(A,1); +retx = origx + xpad(1) + xpad(2); +rety = origy + ypad(1) + ypad(2); + +empty_list_elements_ok = 1; +warn_empty_list_elements = 0; + +if(strcmp(padding, "zeros")) + retval = zeros(rety,retx); + retval(ypad(1)+1 : ypad(1)+origy, xpad(1)+1 : xpad(1)+origx) = A; + elseif(strcmp(padding,"ones")) + retval = ones(rety,retx); + retval(ypad(1)+1 : ypad(1)+origy, xpad(1)+1 : xpad(1)+origx) = A; + elseif(strcmp(padding,"constant")) + retval = const.*ones(rety,retx); + retval(ypad(1)+1 : ypad(1)+origy, xpad(1)+1 : xpad(1)+origx) = A; + elseif(strcmp(padding,"replicate")) + y1 = origy-ypad(1)+1; + x1 = origx-xpad(1)+1; + if(y1 < 1 || x1 < 1 || ypad(2) > origy || xpad(2) > origx) + error("Too large padding for this padding type"); + else + yrange1 = y1 : origy; + yrange2 = 1 : ypad(2); + xrange1 = x1 : origx; + xrange2 = 1 : xpad(2); + retval = [ A(yrange1, xrange1), A(yrange1, :), A(yrange1, xrange2); + A(:, xrange1), A, A(:, xrange2); + A(yrange2, xrange1), A(yrange2, :), A(yrange2, xrange2) ]; + endif + elseif(strcmp(padding,"symmetric")) + y2 = origy-ypad(2)+1; + x2 = origx-xpad(2)+1; + if(ypad(1) > origy || xpad(1) > origx || y2 < 1 || x2 < 1) + error("Too large padding for this padding type"); + else + yrange1 = 1 : ypad(1); + yrange2 = y2 : origy; + xrange1 = 1 : xpad(1); + xrange2 = x2 : origx; + retval = [ fliplr(flipud(A(yrange1, xrange1))), flipud(A(yrange1, :)), fliplr(flipud(A(yrange1, xrange2))); + fliplr(A(:, xrange1)), A, fliplr(A(:, xrange2)); + fliplr(flipud(A(yrange2, xrange1))), flipud(A(yrange2, :)), fliplr(flipud(A(yrange2, xrange2))) ]; + endif + elseif(strcmp(padding,"reflect")) + y2 = origy-ypad(2); + x2 = origx-xpad(2); + if(ypad(1)+1 > origy || xpad(1)+1 > origx || y2 < 1 || x2 < 1) + error("Too large padding for this padding type"); + else + yrange1 = 2 : ypad(1)+1; + yrange2 = y2 : origy-1; + xrange1 = 2 : xpad(1)+1; + xrange2 = x2 : origx-1; + retval = [ fliplr(flipud(A(yrange1, xrange1))), flipud(A(yrange1, :)), fliplr(flipud(A(yrange1, xrange2))); + fliplr(A(:, xrange1)), A, fliplr(A(:, xrange2)); + fliplr(flipud(A(yrange2, xrange1))), flipud(A(yrange2, :)), fliplr(flipud(A(yrange2, xrange2))) ]; + endif + else + error("Unknown padding type"); +endif + +unwind_protect_cleanup + empty_list_elements_ok = empty_list_elements_ok_save; + warn_empty_list_elements = warn_empty_list_elements_save; +end_unwind_protect + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imread.m @@ -0,0 +1,159 @@ +## Copyright (C) 2002 Andy Adler +## +## This program is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. USE THIS SOFTWARE AT YOUR OWN RISK. + +## usage: I = imread(fname) +## +## Read images from various file formats. +## +## The size and numeric class of the output depends on the +## format of the image. A colour image is returned as an +## MxNx3 matrix. Grey-level and black-and-white images are +## of size MxN. +## The colour depth of the image determines the numeric +## class of the output: 'uint8' or 'uint16' for grey +## and colour, and 'logical' for black and white. +## +## Note: For image formats other than jpeg and png, the +## ImageMagick "convert" and "identify" utilities +## are needed. ImageMagick can be found at +## +## www.imagemagick.org +## + +## Author: Andy Adler +## +## Modified: Stefan van der Walt <stefan@sun.ac.za> +## Date: 24 January 2005 + +function varargout = imread(filename, varargin) + if (nargin != 1) + usage("I = imread(filename)") + endif + + if !isstr(filename) + error("imread: filename must be a string") + endif + + fn = file_in_path(IMAGE_PATH, filename); + if isempty(fn) + error("imread: cannot find %s", filename); + endif + + + [ig, ig, ext] = fileparts(fn); + ext = upper(ext); + + ## divert jpegs and pngs to "jpgread" and "pngread" + if ( file_in_loadpath("jpgread.oct") && + (strcmp(ext, ".JPG") || strcmp(ext, ".JPEG")) ) + varargout{1} = jpgread(fn); + break + endif + if ( file_in_loadpath("pngread.oct") && (strcmp(ext, ".PNG")) ) + varargout{1} = pngread(fn); + break + endif + + ## alternately, use imagemagick + if ( file_in_loadpath("__magick_read__.oct") ) + varargout{:} = __magick_read__(fn, varargin{:}); + break + endif + + [sys, ident] = system(sprintf('identify -verbose %s | grep -e "Red: " -e Type', + fn)); + if (sys != 0) + error("imread: error running ImageMagick's 'identify' on %s", fn) + endif + depth = re_grab("Red: ([[:digit:]]{1,2})", ident); + imtype = re_grab("Type: ([[:alpha:]]*)", ident); + + depth = str2num(depth); + if isempty(depth) || (pow2(nextpow2(depth)) != depth) + error("imread: invalid image depth %s", depth) + endif + + if !(strcmp(imtype, "Bilevel") || strcmp(imtype, "Grayscale") || + strcmp(imtype, "TrueColor")) + error("imread: unknown image type '%s'", imtype); + endif + + switch (imtype) + case("Bilevel") + fmt = "pgm"; + case("Grayscale") + fmt = "pgm"; + case("TrueColor") + fmt = "ppm"; + endswitch + + ## Why are pipes so slow? + ## cmd = sprintf("convert -flatten -strip %s %s:-", fn, fmt); + + tmpf = [tmpnam(), ".", fmt]; + cmd = sprintf("convert -flatten -strip +compress '%s' '%s' 2>/dev/null", + fn, tmpf); + + sys = system(cmd); + if (sys != 0) + error("imread: error running ImageMagick's 'convert'"); + unlink(tmpf); + endif + + try + fid = fopen(tmpf, "rb"); + catch + unlink(tmpf); + error("imread: could not open temporary file %s", tmpf) + end_try_catch + + fgetl(fid); # P5 or P6 (pgm or ppm) + [width, height] = sscanf(fgetl(fid), "%d %d", "C"); + fgetl(fid); # ignore max components + + if (depth == 16) + ## PGM format has MSB first, i.e. big endian + [data, count] = fread(fid, "uint16", 0, "ieee-be"); + else + [data, count] = fread(fid, "uint8"); + endif + + fclose(fid); + unlink(tmpf); + + if (imtype == "TrueColor") + channels = 3; + else + channels = 1; + endif + if (count != width*height*channels) + error("imread: image data chunk has invalid size") + endif + + varargout = {}; + switch (imtype) + case ("Bilevel") + varargout{1} = logical(reshape(data, width, height)'); + case ("Grayscale") + varargout{1} = uint8(reshape(data, width, height)'); + case ("TrueColor") + varargout{1} = cat(3, reshape(data(1:3:end), width, height)', + reshape(data(2:3:end), width, height)', + reshape(data(3:3:end), width, height)'); + eval(sprintf("varargout{1} = uint%d(varargout{1});", depth)); + + endswitch +endfunction + +function value = re_grab(re, str) + T = regexp(str,re,'tokens'); + if (isempty(T)) + value = ""; + else + value = T{1}{1}; + endif +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imresize.m @@ -0,0 +1,104 @@ +## Copyright (C) 2005 Søren Hauberg +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{B}= imresize (@var{A}, @var{m}) +## Scales the image @var{A} by a factor @var{m} using nearest neighbour +## interpolation. If @var{m} is less than 1 the image size will be reduced, +## and if @var{m} is greater than 1 the image will be enlarged. If the image +## is being enlarged the it will be convolved with a 11x11 Gaussian FIR filter +## to reduce aliasing. See below on how to alter this behavior. +## +## @deftypefnx {Function File} @var{B}= imresize (@var{A}, @var{m}, @var{method}) +## Same as above except @var{method} interpolation is performed instead of +## using nearest neighbour. @var{method} can be any method supported by interp2. +## +## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}]) +## Scales the image @var{A} to be of size @var{mrow}x@var{mcol} using nearest +## neighbour interpolation. If the image is being enlarged it will be convolved +## with a lowpass FIR filter as described above. +## +## @deftypefnx {Function File} @var{B}= imresize (@var{A}, [@var{mrow} @var{mcol}], @var{method}) +## Same as above except @var{method} interpolation is performed instead of using +## nearest neighbour. @var{method} can be any method supported by interp2. +## +## @deftypefnx {Function File} @var{B}= imresize (..., @var{method}, @var{fsize}) +## If the image the image is being enlarged it will usually be convolved with +## a 11x11 Gaussian FIR filter. By setting @var{fsize} to 0 this will be turned +## off, and if @var{fsize} > 0 the image will be convolved with a @var{fsize} +## by @var{fsize} Gaussian FIR filter. +## +## @deftypefnx {Function File} @var{B}= imresize (..., @var{method}, @var{filter}) +## If the image size is being reduced and the @var{filter} argument is passed to +## imresize the image will be convolved with @var{filter} before the resizing +## takes place. +## +## @seealso{interp2} +## @end deftypefn + +## Author: Søren Hauberg <hauberg at gmail dot com> +## +## 2005-04-14 Søren Hauberg <hauberg at gmail dot com> +## * Initial revision + +function [ ret ] = imresize (im, m, method, filter) + if (!isgray(im)) + error("The first argument has to be a gray-scale image."); + endif + [row col] = size(im); + + # Handle the argument that describes the size of the result + if (length(m) == 1) + new_row = round(row*m); + new_col = round(col*m); + elseif (length(m) == 2) + new_row = m(1); + new_col = m(2); + m = min( new_row/row, new_col/col ); + else + error("Bad second argument"); + end + + # Handle the method argument + if (nargin < 3) + method = "nearest"; + endif + + # Handle the filterargument + if (!strcmp(method, "nearest")) + if (nargin < 4) + filter = 11; + endif + if (m > 1 & filter > 0) + # If the image is being enlarged and filter > 0 then + # convolve the image with a filter*filter gaussian. + mu = round(filter/2); + sigma = mu/3; + x = 1:filter; + gauss = 1/sqrt(2*pi*sigma^2) * exp( (-(x-mu).^2)/(2*sigma^2) ); + im = conv2(gauss, gauss, im, "same"); + elseif (m < 1 & nargin == 4) + # If the image size is being reduced and a fourth argument + # is given, use it as a FIR filter. + im = conv2(im, filter, "same"); + endif + endif + + # Perform the actual resizing + [XI YI] = meshgrid( linspace(1,col,new_col), linspace(1,row,new_row) ); + ret = interp2(im, XI, YI, method); + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imrotate.m @@ -0,0 +1,349 @@ +## Copyright (C) 2004-2005 Justus H. Piater +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} +## imrotate(@var{imgPre}, @var{theta}, @var{method}, @var{bbox}) +## Rotation of a 2D matrix about its center. +## +## Input parameters: +## +## @var{imgPre} a gray-level image matrix +## +## @var{theta} the rotation angle in degrees counterclockwise +## +## @var{method} +## @itemize @w +## @item "nearest" neighbor: fast, but produces aliasing effects (default). +## @item "bilinear" interpolation: does anti-aliasing, but is slightly slower. +## @item "bicubic" interpolation: does anti-aliasing, preserves edges better than bilinear interpolation, but gray levels may slightly overshoot at sharp edges. This is probably the best method for most purposes, but also the slowest. +## @item "Fourier" uses Fourier interpolation, decomposing the rotation matrix into 3 shears. This method often results in different artifacts than homography-based methods. Instead of slightly blurry edges, this method can result in ringing artifacts (little waves near high-contrast edges). However, Fourier interpolation is better at maintaining the image information, so that unrotating will result in an image closer to the original than the other methods. +## @end itemize +## +## @var{bbox} +## @itemize @w +## @item "loose" grows the image to accommodate the rotated image (default). +## @item "crop" rotates the image about its center, clipping any part of the image that is moved outside its boundaries. +## @end itemize +## +## Output parameters: +## +## @var{imgPost} the rotated image matrix +## +## @var{H} the homography mapping original to rotated pixel +## coordinates. To map a coordinate vector c = [x;y] to its +## rotated location, compute round((@var{H} * [c; 1])(1:2)). +## @end deftypefn + +## Author: Justus H. Piater <Justus.Piater@ULg.ac.be> +## Created: 2004-10-18 +## Version: 0.7 + +function [imgPost, H] = imrotate(imgPre, thetaDeg, method, bbox) + if (nargin < 4) + bbox = "loose"; + if (nargin < 3) + method = "nearest"; + if (nargin < 2) + usage("imrotate(img, angle [, method [, bbox]]"); + endif + endif + endif + + thetaDeg = mod(thetaDeg, 360); # some code below relies on positive angles + theta = thetaDeg * pi/180; + + sizePre = size(imgPre); + + ## We think in x,y coordinates here (rather than row,column), except + ## for size... variables that follow the usual size() convention. The + ## coordinate system is aligned with the pixel centers. + + R = [cos(theta) sin(theta); -sin(theta) cos(theta)]; + + if (nargin >= 4 && strcmp(bbox, "crop")) + sizePost = sizePre; + else + ## Compute new size by projecting zero-base image corner pixel + ## coordinates through the rotation: + corners = [0, 0; + (R * [sizePre(2) - 1; 0 ])'; + (R * [sizePre(2) - 1; sizePre(1) - 1])'; + (R * [0 ; sizePre(1) - 1])' ]; + sizePost(2) = round(max(corners(:,1)) - min(corners(:,1))) + 1; + sizePost(1) = round(max(corners(:,2)) - min(corners(:,2))) + 1; + ## This size computation yields perfect results for 0-degree (mod + ## 90) rotations and, together with the computation of the center of + ## rotation below, yields an image whose corresponding region is + ## identical to "crop". However, we may lose a boundary of a + ## fractional pixel for general angles. + endif + + ## Compute the center of rotation and the translational part of the + ## homography: + oPre = ([ sizePre(2); sizePre(1)] + 1) / 2; + oPost = ([sizePost(2); sizePost(1)] + 1) / 2; + T = oPost - R * oPre; # translation part of the homography + + ## And here is the homography mapping old to new coordinates: + H = [[R; 0 0] [T; 1]]; + + ## Treat trivial rotations specially (multiples of 90 degrees): + if (mod(thetaDeg, 90) == 0) + nRot90 = mod(thetaDeg, 360) / 90; + if (mod(thetaDeg, 180) == 0 || sizePre(1) == sizePre(2) || + strcmp(bbox, "loose")) + imgPost = rot90(imgPre, nRot90); + return; + elseif (mod(sizePre(1), 2) == mod(sizePre(2), 2)) + ## Here, bbox is "crop" and the rotation angle is +/- 90 degrees. + ## This works only if the image dimensions are of equal parity. + imgRot = rot90(imgPre, nRot90); + imgPost = zeros(sizePre); + hw = min(sizePre) / 2 - 0.5; + imgPost (round(oPost(2) - hw) : round(oPost(2) + hw), + round(oPost(1) - hw) : round(oPost(1) + hw) ) = ... + imgRot(round(oPost(1) - hw) : round(oPost(1) + hw), + round(oPost(2) - hw) : round(oPost(2) + hw) ); + return; + else + ## Here, bbox is "crop", the rotation angle is +/- 90 degrees, and + ## the image dimensions are of unequal parity. This case cannot + ## correctly be handled by rot90() because the image square to be + ## cropped does not align with the pixels - we must interpolate. A + ## caller who wants to avoid this should ensure that the image + ## dimensions are of equal parity. + endif + end + + ## For better readability of this spaghetti implementation, I keep the + ## branches pertaining to the various 'method's all at the first + ## level, even though this causes a slight redundancy in the if + ## statements. + + imgPost = []; + + if (strcmp(method, "Fourier")) + imgPost = imrotate_Fourier(imgPre, thetaDeg, method, bbox); + else + ## This section pertains to all non-Fourier methods. + + ## "Pre" variables hold pre -rotation values; + ## "Post" variables hold post-rotation values. + + ## General rotation: map pixel coordinates back from the Post to the + ## Pre img + Hinv = inv(H); + + ## Target coordinates: + [xPost, yPost] = meshgrid(1:(sizePost(2)), 1:(sizePost(1))); + + ## Compute corresponding source coordinates: + xPre = Hinv(1,1) * xPost + Hinv(1,2) * yPost + Hinv(1,3); + yPre = Hinv(2,1) * xPost + Hinv(2,2) * yPost + Hinv(2,3); + ## zPre is guaranteed to be 1, since the last row of H (and thus of + ## Hinv) is [0 0 1]. + endif + + ## Now map the image using the coordinates computed in the else branch above: + if (strcmp(method, "nearest")) + ## nearest-neighbor: simply round Pre coordinates + xPre = round(xPre); + yPre = round(yPre); + valid = find(1 <= xPre & xPre <= sizePre(2) & + 1 <= yPre & yPre <= sizePre(1) ); + if (!length(valid)) + warning("input image too small"); + imgPost = 0; + return; + endif + + iPre = sub2ind(sizePre , yPre (valid), xPre (valid)); + iPost = sub2ind(sizePost, yPost(valid), xPost(valid)); + + imgPost = zeros(sizePost); + imgPost(iPost) = imgPre(iPre); + elseif(!strcmp(method, "Fourier")) + ## This section pertains to "bilinear" and "bicubic" methods. + + ## With interpolation, one unavoidably loses up to one or two pixel + ## rows or columns at the image boundaries. + + xPreFloor = floor(xPre); + xPreCeil = ceil (xPre); + yPreFloor = floor(yPre); + yPreCeil = ceil (yPre); + + valid = find(1 <= xPreFloor & xPreCeil <= sizePre(2) & + 1 <= yPreFloor & yPreCeil <= sizePre(1) ); + if (!length(valid)) + warning("input image too small"); + imgPost = 0; + return; + endif + + xPreFloor = xPreFloor(valid); + xPreCeil = xPreCeil (valid); + yPreFloor = yPreFloor(valid); + yPreCeil = yPreCeil (valid); + + ## In the following, FC = floor(x), ceil(y), etc. + iPreFF = sub2ind(sizePre, yPreFloor, xPreFloor); + iPreCF = sub2ind(sizePre, yPreFloor, xPreCeil ); + iPreCC = sub2ind(sizePre, yPreCeil , xPreCeil ); + iPreFC = sub2ind(sizePre, yPreCeil , xPreFloor); + + ## We'll have to weight by the fractional part of the coordinates: + xPreFrac = xPre(valid) - xPreFloor; + yPreFrac = yPre(valid) - yPreFloor; + + iPost = sub2ind(sizePost, yPost(valid), xPost(valid)); + endif + + if (strcmp(method, "bilinear")) + imgPost = zeros(sizePost); + ## bilinear interpolation between the four floor and ceiling coordinates + imgPost(iPost) = (imgPre(iPreFF) .* (1 - xPreFrac) .* (1 - yPreFrac) + + imgPre(iPreCF) .* xPreFrac .* (1 - yPreFrac) + + imgPre(iPreCC) .* xPreFrac .* yPreFrac + + imgPre(iPreFC) .* (1 - xPreFrac) .* yPreFrac ); + elseif (strcmp(method, "bicubic")) + ## bicubic interpolation (see Numerical Recipes) + ## This code, together with the prerequisites above, is not limited + ## to this particular use but applies to generic bicubic + ## interpolation in the following scenario: + ## - source data are stored in a matrix, + ## - interpolated coordinates may lie anywhere, no regularity is assumed. + + ## precompute the required derivatives at the source image pixels: + imgPreDx = conv2(imgPre , [ 0.5 0 -0.5] , "same"); + imgPreDy = conv2(imgPre , [-0.5 0 0.5]', "same"); + imgPreDxy = conv2(imgPreDx, [-0.5 0 0.5]', "same"); + + ## Interpolation is done on a square of pixels and their + ## derivatives along x, y, and xy. The square is indexed as: + ## 43 FF CF + ## 12 which corresponds to FC CC + + ## Coefficient matrix W + ## C11 12 21 31 41 p deriv + W = [1 0 -3 2 0 0 0 0 -3 0 9 -6 2 0 -6 4 ## 1 + 0 0 0 0 0 0 0 0 3 0 -9 6 -2 0 6 -4 ## 2 + 0 0 0 0 0 0 0 0 0 0 9 -6 0 0 -6 4 ## 3 + 0 0 3 -2 0 0 0 0 0 0 -9 6 0 0 6 -4 ## 4 + + 0 0 0 0 1 0 -3 2 -2 0 6 -4 1 0 -3 2 ## 1 x + 0 0 0 0 0 0 0 0 -1 0 3 -2 1 0 -3 2 ## 2 x + 0 0 0 0 0 0 0 0 0 0 -3 2 0 0 3 -2 ## 3 x + 0 0 0 0 0 0 3 -2 0 0 -6 4 0 0 3 -2 ## 4 x + + 0 1 -2 1 0 0 0 0 0 -3 6 -3 0 2 -4 2 ## 1 y + 0 0 0 0 0 0 0 0 0 3 -6 3 0 -2 4 -2 ## 2 y + 0 0 0 0 0 0 0 0 0 0 -3 3 0 0 2 -2 ## 3 y + 0 0 -1 1 0 0 0 0 0 0 3 -3 0 0 -2 2 ## 4 y + + 0 0 0 0 0 1 -2 1 0 -2 4 -2 0 1 -2 1 ## 1 xy + 0 0 0 0 0 0 0 0 0 -1 2 -1 0 1 -2 1 ## 2 xy + 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 -1 1 ## 3 xy + 0 0 0 0 0 0 -1 1 0 0 2 -2 0 0 -1 1]; ## 4 xy + + u = 1 - yPreFrac; + values = zeros(size(valid)); + for ci = 4:-1:1 + ## compute ci'th row of matrix C: + + col = 4*(ci - 1) + 1; + c{1} = (W( 1,col) * imgPre (iPreFC) + W( 2,col) * imgPre (iPreCC) + + W( 5,col) * imgPreDx (iPreFC) + W( 6,col) * imgPreDx (iPreCC) ); + + col++; + c{2} = (W( 9,col) * imgPreDy (iPreFC) + W(10,col) * imgPreDy (iPreCC) + + W(13,col) * imgPreDxy(iPreFC) + W(14,col) * imgPreDxy(iPreCC) ); + + for cii = 3:4 + col++; + c{cii} = ... + (W( 1,col) * imgPre (iPreFC) + W( 2,col) * imgPre (iPreCC) + + W( 3,col) * imgPre (iPreCF) + W( 4,col) * imgPre (iPreFF) + + W( 5,col) * imgPreDx (iPreFC) + W( 6,col) * imgPreDx (iPreCC) + + W( 7,col) * imgPreDx (iPreCF) + W( 8,col) * imgPreDx (iPreFF) + + W( 9,col) * imgPreDy (iPreFC) + W(10,col) * imgPreDy (iPreCC) + + W(11,col) * imgPreDy (iPreCF) + W(12,col) * imgPreDy (iPreFF) + + W(13,col) * imgPreDxy(iPreFC) + W(14,col) * imgPreDxy(iPreCC) + + W(15,col) * imgPreDxy(iPreCF) + W(16,col) * imgPreDxy(iPreFF) ); + endfor + + values .*= xPreFrac; + values += ((c{4} .* u + c{3}) .* u + c{2}) .* u + c{1}; + endfor + imgPost = zeros(sizePost); + imgPost(iPost) = values; + endif + + if (!prod(size(imgPost))) + error(sprintf("Interpolation method %s not implemented", method)); + endif +endfunction + +%!test +%! ## Verify minimal loss across six rotations that add up to 360 +/- 1 deg.: +%! methods = { "nearest", "bilinear", "bicubic", "Fourier" }; +%! angles = [ 59 60 61 ]; +%! tolerances = [ 7.4 8.5 8.6 # nearest +%! 3.5 3.1 3.5 # bilinear +%! 2.7 0.1 2.7 # bicubic +%! 2.7 1.6 2.8 ]; # Fourier +%! x = peaks(50); +%! x -= min(min(x)); # Fourier does not handle neg. values well +%! for m = 1:(length(methods)) +%! y = x; +%! for i = 1:5 +%! y = imrotate(y, 60, methods(m), "crop"); +%! end +%! for a = 1:(length(angles)) +%! assert(norm((x - imrotate(y, angles(a), methods(m), "crop")) +%! (10:40, 10:40)) < tolerances(m,a)); +%! end +%! end + + +%!test +%! ## Verify exactness of near-90 and 90-degree rotations: +%! X = rand(99); +%! for angle = [90 180 270] +%! for da = [-0.1 0.1] +%! Y = imrotate(X, angle + da , "nearest"); +%! Z = imrotate(Y, -(angle + da), "nearest"); +%! assert(norm(X - Z) == 0); # exact zero-sum rotation +%! assert(norm(Y - imrotate(X, angle, "nearest")) == 0); # near zero-sum +%! end +%! end + + +%!test +%! ## Verify preserved pixel density: +%! methods = { "nearest", "bilinear", "bicubic", "Fourier" }; +%! ## This test does not seem to do justice to the Fourier method...: +%! tolerances = [ 4 2.2 2.0 209 ]; +%! range = 3:9:100; +%! for m = 1:(length(methods)) +%! t = []; +%! for n = range +%! t(end + 1) = sum(imrotate(eye(n), 20, methods(m))(:)); +%! end +%! assert(t, range, tolerances(m)); +%! end +
new file mode 100644 --- /dev/null +++ b/inst/imrotate_Fourier.m @@ -0,0 +1,170 @@ +## Copyright (C) 2002 Jeff Orchard <jorchard@cs.uwaterloo.ca> +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} imrotate(@var{M}, @var{theta}, @var{method}, @var{bbox}) +## Rotation of a 2D matrix. +## +## Applies a rotation of @var{THETA} degrees to matrix @var{M}. +## +## The @var{method} argument is not implemented, and is only included for compatibility with Matlab. +## This function uses Fourier interpolation, +## decomposing the rotation matrix into 3 shears. +## +## @var{bbox} can be either 'loose' or 'crop'. +## 'loose' allows the image to grow to accomodate the rotated image. +## 'crop' keeps the same size as the original, clipping any part of the image +## that is moved outside the bounding box. +## @end deftypefn + +## Author: Jeff Orchard <jorchard@cs.uwaterloo.ca> +## Created: Oct. 14, 2002 + +function fs = imrotate_Fourier(f,theta,method,bbox) + + if ( nargin == 2 ) + method = "fourier"; + bbox = "loose"; + elseif ( nargin == 3 ) + bbox = "loose"; + endif + + # Get original dimensions. + [ydim_orig, xdim_orig] = size(f); + + # This finds the index coords of the centre of the image (indices are base-1) + # eg. if xdim_orig=8, then xcentre_orig=4.5 (half-way between 1 and 8) + xcentre_orig = (xdim_orig+1) / 2; + ycentre_orig = (ydim_orig+1) / 2; + + # Pre-process the angle =========================================================== + # Whichever 90 degree multiple theta is closest to, that multiple of 90 will + # be implemented by rot90. The remainder will be done by shears. + + # This ensures that 0 <= theta < 360. + theta = rem( rem(theta,360) + 360, 360 ); + + # This is a flag to keep track of 90-degree rotations. + perp = 0; + + if ( theta>=0 && theta<=45 ) + phi = theta; + elseif ( theta>45 && theta<=135 ) + phi = theta - 90; + f = rot90(f,1); + perp = 1; + elseif ( theta>135 && theta<=225 ) + phi = theta - 180; + f = rot90(f,2); + elseif ( theta>225 && theta<=315 ) + phi = theta - 270; + f = rot90(f,3); + perp = 1; + else + phi = theta; + endif + + + + if ( phi == 0 ) + fs = f; + if ( strcmp(bbox,"loose") == 1 ) + return; + else + xmax = xcentre_orig; + ymax = ycentre_orig; + if ( perp == 1 ) + xmax = max([xmax ycentre_orig]); + ymax = max([ymax xcentre_orig]); + [ydim xdim] = size(fs); + xpad = ceil( xmax - (xdim+1)/2 ); + ypad = ceil( ymax - (ydim+1)/2 ); + fs = impad(fs, [xpad,xpad], [ypad,ypad], "zeros"); + endif + xcentre_new = (size(fs,2)+1) / 2; + ycentre_new = (size(fs,1)+1) / 2; + endif + else + + # At this point, we can assume -45<theta<45 (degrees) + + phi = phi * pi / 180; + theta = theta * pi / 180; + R = [ cos(theta) -sin(theta) ; sin(theta) cos(theta) ]; + + # Find max of each dimension... this will be expanded for "loose" and "crop" + xmax = xcentre_orig; + ymax = ycentre_orig; + + # If we don't want wrapping, we have to zeropad. + # Cropping will be done later, if necessary. + if ( strcmp(bbox, "wrap") == 0 ) + corners = ( [ xdim_orig xdim_orig -xdim_orig -xdim_orig ; ydim_orig -ydim_orig ydim_orig -ydim_orig ] + 1 )/ 2; + rot_corners = R * corners; + xmax = max([xmax rot_corners(1,:)]); + ymax = max([ymax rot_corners(2,:)]); + + # If we are doing a 90-degree rotation first, we need to make sure our + # image is large enough to hold the rot90 image as well. + if ( perp == 1 ) + xmax = max([xmax ycentre_orig]); + ymax = max([ymax xcentre_orig]); + endif + + [ydim xdim] = size(f); + xpad = ceil( xmax - xdim/2 ); + ypad = ceil( ymax - ydim/2 ); + %f = impad(f, [xpad,xpad], [ypad,ypad], "zeros"); + xcentre_new = (size(f,2)+1) / 2; + ycentre_new = (size(f,1)+1) / 2; + endif + + #size(f) + [S1 S2] = MakeShears(phi); + + tic; + f1 = imshear(f, 'x', S1(1,2), 'loose'); + f2 = imshear(f1, 'y', S2(2,1), 'loose'); + fs = real( imshear(f2, 'x', S1(1,2), 'loose') ); + %fs = f2; + xcentre_new = (size(fs,2)+1) / 2; + ycentre_new = (size(fs,1)+1) / 2; + endif + + if ( strcmp(bbox, "crop") == 1 ) + + # Translate the current centre to centre_orig + fs = imtranslate(fs, xcentre_orig-xcentre_new, -ycentre_orig+ycentre_new, "wrap"); + + # Crop to original dimensions + fs = fs(1:ydim_orig, 1:xdim_orig); + + elseif ( strcmp(bbox, "loose") == 1 ) + + # Find tight bounds on size of rotated image + # These should all be positive, or 0. + xmax_loose = ceil( xcentre_new + max(rot_corners(1,:)) ); + xmin_loose = floor( xcentre_new - max(rot_corners(1,:)) ); + ymax_loose = ceil( ycentre_new + max(rot_corners(2,:)) ); + ymin_loose = floor( ycentre_new - max(rot_corners(2,:)) ); + + %fs = fs( (ymin_loose+1):(ymax_loose-1) , (xmin_loose+1):(xmax_loose-1) ); + fs = fs( (ymin_loose+1):(ymax_loose-1) , (xmin_loose+1):(xmax_loose-1) ); + + endif + + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imshear.m @@ -0,0 +1,131 @@ +## Copyright (C) 2002 Jeff Orchard +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} +## imshear (@var{M}, @var{axis}, @var{alpha}, @var{bbox}) +## Applies a shear to @var{M}. +## +## The argument @var{M} is either a matrix or an RGB image. +## +## @var{axis} is the axis along which the shear is to be applied, and can +## be either 'x' or 'y'. +## For example, to shear sideways is to shear along the 'x' axis. Choosing +## 'y' causes an up/down shearing. +## +## @var{alpha} is the slope of the shear. For an 'x' shear, it is the +## horizontal shift (in pixels) applied to the pixel above the +## center. For a 'y' shear, it is the vertical shift (in pixels) +## applied to the pixel just to the right of the center pixel. +## +## NOTE: @var{alpha} does NOT need to be an integer. +## +## @var{bbox} can be one of 'loose', 'crop' or 'wrap'. +## 'loose' allows the image to grow to accomodate the new transformed image. +## 'crop' keeps the same size as the original, clipping any part of the image +## that is moved outside the bounding box. +## 'wrap' keeps the same size as the original, but does not clip the part +## of the image that is outside the bounding box. Instead, it wraps it back +## into the image. +## +## If called with only 3 arguments, @var{bbox} is set to 'loose' by default. +## @end deftypefn + +## Author: Jeff Orchard <jjo@sfu.ca> +## Created: June 2002 + +function g = imshear(m, axis, alpha, bbox, noshift) + + # The code below only does y-shearing. This is because of + # the implementation of fft (operates on columns, but not rows). + # So, transpose first for x-shearing. + if ( strcmp(axis, "x")==1 ) + m = m'; + endif + + if ( nargin < 4 ) + bbox = "loose"; + noshift = 0; + elseif ( nargin < 5 ) + noshift = 0; + endif + + [ydim_orig xdim_orig] = size(m); + if ( strcmp(bbox, "wrap") == 0 ) + ypad = ceil( (xdim_orig+1)/2 * abs(alpha) ); + m = impad(m, [0,0], [ypad,ypad]); + endif + + [ydim_new xdim_new] = size(m); + xcentre = ( xdim_new + 1 ) / 2; + ycentre = ( ydim_new + 1 ) / 2; + + # This applies FFT to columns of m (x-axis remains a spatial axis). + # Because the way that fft and fftshift are implemented, the origin + # will move by 1/2 pixel, depending on the polarity of the image + # dimensions. + # + # If dim is even (=2n), then the origin of the fft below is located + # at the centre of pixel (n+1). ie. if dim=16, then centre is at 9. + # + # If dim is odd (=2n+1), then the origin of the fft below is located + # at the centre of pixel (n). ie. if dim=15, then centre is at 8. + if ( noshift==1 ) + M = fft(m); + else + #M = imtranslate(fft(imtranslate(m, -xcentre, ycentre, "wrap")), xcentre, -ycentre, "wrap"); + M = fftshift(fft(fftshift(m))); + endif + + [ydim xdim] = size(m); + x = zeros(ydim, xdim); + + # Find coords of the origin of the image. + if ( noshift==1 ) + xc_coord = 1; + yc_coord = 1; + l = (1:ydim)' - yc_coord; + r = (1:xdim) - xc_coord; + if ( strcmp(bbox, "wrap")==1 ) + l((ydim/2):ydim) = l((ydim/2):ydim) - ydim; + r((xdim/2):xdim) = r((xdim/2):xdim) - xdim; + endif + else + xc_coord = (xdim+1)/2; + yc_coord = (ydim+1)/2; + l = (1:ydim)' - yc_coord; + r = (1:xdim) - xc_coord; + endif + x = l * r; + + Ms = M.* exp(2*pi*I*alpha/ydim * x); + + if ( noshift==1 ) + g = abs(ifft(Ms)); + else + #g = abs(imtranslate( ifft( imtranslate(Ms, -xcentre, ycentre, "wrap") ), xcentre, -ycentre, "wrap")); + g = abs( fftshift(ifft(ifftshift(Ms))) ); + endif + + if ( strcmp(bbox, "crop")==1 ) + g = g(ypad+1:ydim_orig+ypad, :); + endif + + # Un-transpose if x-shearing was wanted + if ( strcmp(axis, "x")==1 ) + g = g'; + endif +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imtranslate.m @@ -0,0 +1,70 @@ +## Copyright (C) 2002 Jeff Orchard +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{Y}} = +## imtranslate (@var{M}, @var{x}, @var{y} [, @var{bbox}]) +## Translate a 2D image by (x,y) using Fourier interpolation. +## +## @var{M} is a matrix, and is translated to the right by @var{X} pixels +## and translated up by @var{Y} pixels. +## +## @var{bbox} can be either 'crop' or 'wrap' (default). +## +## @end deftypefn + +## Author: Jeff Orchard <jjo@cs.sfu.ca> + +function Y = imtranslate(X, a, b, bbox_in) + + bbox = "wrap"; + if ( nargin > 3 ) + bbox = bbox_in; + endif + + if ( strcmp(bbox, "crop")==1 ) + + xpad = [0,0]; + if (a>0) + xpad = [0,ceil(a)]; + elseif (a<0) + xpad = [-ceil(a),0]; + endif + + ypad = [0,0]; + if (b>0) + ypad = [ceil(b),0]; + elseif (b<0) + ypad = [0,-ceil(b)]; + endif + + X = impad(X, xpad, ypad, 'zeros'); + endif + + + [dimy, dimx] = size(X); + x = ifftshift(fft2(fftshift(X))); + px = exp(-2*pi*i*a*(0:dimx-1)/dimx); + py = exp(-2*pi*i*b*(0:dimy-1)/dimy)'; + P = py * px; + y = x .* P; + Y = abs( ifftshift(ifft2(fftshift(y))) ); + #Y = ifftshift(ifft2(fftshift(y))); + + if ( strcmp(bbox, "crop")==1 ) + Y = Y( ypad(1)+1:dimy-ypad(2) , xpad(1)+1:dimx-xpad(2)); + endif +endfunction
new file mode 100644 --- /dev/null +++ b/inst/imwrite.m @@ -0,0 +1,276 @@ +## Copyright (C) 2002 Andy Adler +## +## This program is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. USE THIS SOFTWARE AT YOUR OWN RISK. + +#IMWRITE: write image from octave to various file formats +# +# Note: this requires the ImageMagick "convert" utility. +# get this from www.imagemagick.org if required +# additional documentation of options is available from the +# convert man page +# +# BASIC USAGE: +# imwrite( fname, img ) +# - img is a greyscale (0-255) of image in fname +# imwrite( fname, img, map ) +# - map is a matrix of [r,g,b], 0-1 triples +# - img is a matrix on indeces into map +# imwrite( fname, r,g,b ); +# - r,g,b are red,green,blue (0-255) compondents +# +# Formats for image fname +# 1. simple guess from extention ie "fig.jpg", "blah.gif" +# 2. specify explicitly "jpg:fig.jpg", "gif:blah.gif" +# 3. specify subimage for multi-image format "tiff:file.tif[3]" +# 4. raw images (row major format) specify geometry +# "raw:img[256x180]" +# +# IMREAD OPTIONS: +# imread will support most of the options for convert.1 +# +# imwrite( fname, img, options ) +# imwrite( fname, img, map, options ) +# imwrite( fname, r,g,b, options ); +# +# where options is a string matrix (or list) of options +# +# example: options= ["-rotate 25"; +# "-crop 200x200+150+150"; +# "-sample 200%" ]; +# will rotate, crop, and then expand the image. +# note that the order of operations is important +# +# The following options are supported +# -antialias remove pixel-aliasing +# -background color background color +# -blur geometry blur the image +# -border geometry surround image with a border of color +# -bordercolor color border color +# -box color color for annotation bounding box +# -charcoal radius simulate a charcoal drawing +# -colorize value colorize the image with the fill color +# -colors value preferred number of colors in the image +# -colorspace type alternate image colorspace +# -comment string annotate image with comment +# -compress type type of image compression +# -contrast enhance or reduce the image contrast +# -crop geometry preferred size and location of the cropped image +# -density geometry vertical and horizontal density of the image +# -depth value depth of the image +# -despeckle reduce the speckles within an image +# -dispose method GIF disposal method +# -dither apply Floyd/Steinberg error diffusion to image +# -draw string annotate the image with a graphic primitive +# -edge radius apply a filter to detect edges in the image +# -emboss radius emboss an image +# -enhance apply a digital filter to enhance a noisy image +# -equalize perform histogram equalization to an image +# -fill color color to use when filling a graphic primitive +# -filter type use this filter when resizing an image +# -flip flip image in the vertical direction +# -flop flop image in the horizontal direction +# -font name font for rendering text +# -frame geometry surround image with an ornamental border +# -fuzz distance colors within this distance are considered equal +# -gamma value level of gamma correction +# -geometry geometry perferred size or location of the image +# -gaussian geometry gaussian blur an image +# -gravity type vertical and horizontal text placement +# -implode amount implode image pixels about the center +# -intent type Absolute, Perceptual, Relative, or Saturation +# -interlace type None, Line, Plane, or Partition +# -label name assign a label to an image +# -level value adjust the level of image contrast +# -list type Color, Delegate, Format, Magic, Module, or Type +# -map filename transform image colors to match this set of colors +# -matte store matte channel if the image has one +# -median radius apply a median filter to the image +# -modulate value vary the brightness, saturation, and hue +# -monochrome transform image to black and white +# -morph value morph an image sequence +# -negate replace every pixel with its complementary color +# -noise radius add or reduce noise in an image +# -normalize transform image to span the full range of colors +# -opaque color change this color to the fill color +# -page geometry size and location of an image canvas +# -paint radius simulate an oil painting +# -profile filename add ICM or IPTC information profile to image +# -quality value JPEG/MIFF/PNG compression level +# -raise value lighten/darken image edges to create a 3-D effect +# -region geometry apply options to a portion of the image +# -roll geometry roll an image vertically or horizontally +# -rotate degrees apply Paeth rotation to the image +# -sample geometry scale image with pixel sampling +# -scale geometry resize image +# -segment values segment an image +# -seed value pseudo-random number generator seed value +# -shade degrees shade the image using a distant light source +# -sharpen geometry sharpen the image +# -shave geometry shave pixels from the image edges +# -shear geometry slide one edge of the image along the X or Y axis +# -size geometry width and height of image +# -solarize threshold negate all pixels above the threshold level +# -spread amount displace image pixels by a random amount +# -stroke color color to use when stoking a graphic primitive +# -strokewidth value width of stroke +# -swirl degrees swirl image pixels about the center +# -texture filename name of texture to tile onto the image background +# -threshold value threshold the image +# -tile filename tile image when filling a graphic primitive +# -transparent color make this color transparent within the image +# -treedepth value depth of the color tree +# -type type image type +# -units type PixelsPerInch, PixelsPerCentimeter, or Undefined +# -unsharp geometry sharpen the image + +function imwrite(fname, p2, p3 ,p4 ,p5 ); + +try save_empty_list_elements_ok= empty_list_elements_ok; +catch save_empty_list_elements_ok= 0; +end +try save_warn_empty_list_elements= warn_empty_list_elements; +catch save_warn_empty_list_elements= 0; +end +unwind_protect +empty_list_elements_ok= 1; +warn_empty_list_elements= 0; + +# some older versions of octave didn't seem handle piped output correctly +usepipe=1; + +if ( nargin <= 1 ) || ... + ( ! ischar (fname)) || ... + ( nargin == 2 && ischar(p2) ) + usage([ ... + "imwrite( fname, img )\n", ... + "imwrite( fname, img, map )\n", ... + "imwrite( fname, r,g,b );\n", ... + "imwrite( fname, img, options )\n", ... + "imwrite( fname, img, map, options )\n", ... + "imwrite( fname, r,g,b, options );\n"]); +endif + +# Put together the options string +# TODO: add some error checking to options +option_str=""; +n_mat= nargin-1; + +options= eval(sprintf("p%d",nargin)); +# process options strings if given +if ischar(options) + n_mat--; + for i= 1:size(options,1) + option_str=[option_str," ", options(i,:) ]; + end +elseif is_list( options ) + n_mat--; + for i= 1:length(options) + option_str=[option_str," ", nth(options,i) ]; + end +end + +[hig,wid] = size(p2); +if n_mat==1 + data= p2'; + outputtype="pgm"; + pnm_sig="P5"; +elseif n_mat==2 + img= p2'; + data= [ 255*reshape(p3(img,1),1, hig*wid); + 255*reshape(p3(img,2),1, hig*wid); + 255*reshape(p3(img,3),1, hig*wid) ]; + outputtype="ppm"; + pnm_sig="P6"; +elseif n_mat==3 + data= [ reshape(p2',1, hig*wid); + reshape(p3',1, hig*wid); + reshape(p4',1, hig*wid) ]; + outputtype="ppm"; + pnm_sig="P6"; +else + error("imwrite: too many data matrices specified"); +end + +if usepipe + pname= sprintf("convert %s %s:- '%s' 2>/dev/null", + option_str, outputtype, fname); + fid= popen(pname ,'w'); + + if fid<0; + error('could not create image data. Is ImageMagick installed?'); + end +else + tnam= tmpnam(); + cmd= sprintf("convert %s '%s:%s' '%s' 2>/dev/null", + option_str, outputtype, tnam, fname); + fid= fopen(tnam, "wb"); +end + + fprintf(fid,"%s\n%d %d\n255\n",pnm_sig,wid,hig); + write_count= fwrite(fid,data(:)); + if write_count != prod(size(data)) + fclose(fid); + if ~usepipe + unlink(tnam); + end + error(['Problem writing image: ', fname ]); + end + + fclose(fid); + if ~usepipe + retcode = system(cmd); + if retcode !=0 + error('could not call imagemagick convert'); + end + unlink( tnam ); + end + +unwind_protect_cleanup +empty_list_elements_ok= save_empty_list_elements_ok; +warn_empty_list_elements= save_warn_empty_list_elements; +end_unwind_protect + +# +# $Log$ +# Revision 1.1 2006/08/20 12:59:34 hauberg +# Changed the structure to match the package system +# +# Revision 1.11 2006/03/22 17:50:47 qspencer +# Change calls to 'system' function to reflect new ordering of output arguments. +# +# Revision 1.10 2005/09/08 02:00:17 pkienzle +# [for Bill Denney] isstr -> ischar +# +# Revision 1.9 2005/07/21 16:03:02 aadler +# Improve error messages and use pipes +# +# Revision 1.8 2005/05/25 03:43:40 pkienzle +# Author/Copyright consistency +# +# Revision 1.7 2005/04/25 01:05:28 aadler +# added GPL copyrights +# +# Revision 1.6 2003/09/12 14:22:42 adb014 +# Changes to allow use with latest CVS of octave (do_fortran_indexing, etc) +# +# Revision 1.5 2003/07/25 19:11:41 pkienzle +# Make sure all files names referenced in system calls are wrapped in quotes +# to protect against spaces in the path. +# +# Revision 1.4 2002/11/27 08:40:11 pkienzle +# author/license updates +# +# Revision 1.3 2002/03/19 18:14:13 aadler +# unfortunately using popen seems to create problems, mostly +# on win32, but also on linux, so we need to move to a tmpfile approach +# +# Revision 1.2 2002/03/17 05:26:14 aadler +# now accept filenames with spaces +# +# Revision 1.1 2002/03/11 01:56:47 aadler +# general image read/write functionality using imagemagick utilities +# +#
new file mode 100644 --- /dev/null +++ b/inst/isbw.m @@ -0,0 +1,39 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{bool}= isbw (@var{BW}) +## returns true for a black-white (binary) image. +## All values must be either 0 or 1 +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 20/03/2000 + +function bool = isbw (BW) + + bool = 0; + if !(nargin == 1) + usage ("isbw(BW)"); + endif + + if !(is_matrix(BW)) + return; + endif + + bool = all (all ((BW == 1) + (BW == 0))); + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/isgray.m @@ -0,0 +1,40 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{bool}= isgray (@var{I}) +## returns true for an intensity image. All intensity values must +## be in the range [0,1]. +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 20/03/2000 + +function bool = isgray (I) + + bool = 0; + + if !(nargin == 1) + usage ("isgray(I)"); + endif + + if (!is_matrix(I)) + return; + endif + + bool = all (all ((I >= 0) && (I <= 1))); + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/isind.m @@ -0,0 +1,43 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WXTHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABXLXTY or FXTNESS FOR A PARTXCULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Xnc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{bool}= isind (@var{X}) +## returns true for an index image. All index values must +## be intergers and greater than or equal to 1. +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 20/03/2000 + +function ret = isind (X) + + if nargin != 1 + usage ("isind(X)"); + endif + + ret = isreal (X) && length (size (X)) == 2 ... + && all ( X(:) == floor (X(:)) ) && all ( X(:) >= 1 ); + +endfunction + +%!assert(isind([])) +%!assert(isind(1:10)) +%!assert(!isind(0:10)) +%!assert(isind(1)) +%!assert(!isind(0)) +%!assert(!isind([1.3,2.4])) +%!assert(isind([1,2;3,4]))
new file mode 100644 --- /dev/null +++ b/inst/isrgb.m @@ -0,0 +1,81 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{flag} = } isrgb (@var{A}) +## Returns true if parameter is a RGB image +## +## @code{flag=isrgb(A)} returns 1 if @var{A} is a RGB image and 0 if +## not. +## +## To the decide @code{isrgb} uses the follow algorithm: +## @itemize @bullet +## @item +## If @var{A} is of class double then it checks if all values are +## between 0 and 1, and if size is m-by-n-by-3. +## @item +## If @var{A} is of class uint16, uint8 or logical then it checks is m-by-n-by-3. +## @end itemize +## +## @strong{Compatibility notes:} +## +## Information needed on whether MATLAB accepts logical arrays as RGB +## images (now this functions accepts them if they are m-by-n-by-3 arrays. +## +## @end deftypefn + +## TODO: Check if logical arrays should be considered RGB + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function flag = isrgb(A) + if (nargin!=1) + usage("flag=isrgb(A)"); + endif + + if(ismatrix(A)) + flag=1; + s=size(A); + if(length(s)!=3 || s(3)!=3) + flag=0; ## false if not m-by-n-by-3 + elseif(strcmp(typeinfo(A),"matrix") && (any(A(:)<0) || any(A(:)>1))) + flag=0; ## false if class double but items are <0 or >1 + endif + else + flag=0; + endif +endfunction + + +%!demo +%! isrgb(rand(1,2,3)) +%! # A 1-by-2-by-3 double matrix with elements between 0 and 1 is a RGB image. + + +%!# Non-matrix +%!assert(isrgb("this is not a RGB image"),0); + +%!# Double matrix tests +%!assert(isrgb(rand(5,5)),0); +%!assert(isrgb(rand(5,5,1,5)),0); +%!assert(isrgb(rand(5,5,3,5)),0); +%!assert(isrgb(rand(5,5,3)),1); +%!assert(isrgb(ones(5,5,3)),1); +%!assert(isrgb(ones(5,5,3)+.0001),0); +%!assert(isrgb(zeros(5,5,3)-.0001),0); + +%!# Logical +%!assert(isrgb(logical(round(rand(5,5,3)))),1);
new file mode 100644 --- /dev/null +++ b/inst/jet.m @@ -0,0 +1,55 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} jet (@var{n}) +## Create color colormap. +## (dark blue through blue, cyan, green, yellow, red to dark red) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = jet (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("jet: argument must be a scalar"); + endif + else + usage ("jet (number)"); + endif + + if (number == 1) + map = [0, 0, 0.5]; + elseif (number > 1) + x = linspace(0, 1, number)'; + r = (x >= 3/8 & x < 5/8) .* (4 * x - 3/2)\ + + (x >= 5/8 & x < 7/8) + (x >= 7/8) .* (-4 * x + 9/2); + g = (x >= 1/8 & x < 3/8) .* (4 * x - 1/2)\ + + (x >= 3/8 & x < 5/8) + (x >= 5/8 & x < 7/8) .* (-4 * x + 7/2); + b = (x < 1/8) .* (4 * x + 1/2) + (x >= 1/8 & x < 3/8)\ + + (x >= 3/8 & x < 5/8) .* (-4 * x + 5/2); + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/makelut.m @@ -0,0 +1,73 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{lut} = } makelut (@var{fun},@var{n}) +## @deftypefnx {Function File} {@var{lut} = } makelut (@var{fun},@var{n},@var{P1},@var{P2},...) +## Create a lookup table which can be used by applylut. +## +## lut = makelut(fun,n) returns a vector which can be used by applylut +## as a lookup table. +## +## @var{fun} can be a function object as created by inline, or simply a +## string which contains the name of a function. @var{fun} should accept a +## @var{n}-by-@var{n} matrix whose elements are binary (0 or 1) and +## returns an scalar (actually anything suitable to be included in a +## vector). +## +## makelut calls @var{fun} with all possible matrices and builds a +## vector with its result, suitable to be used by applylut. The length +## of this vector is 2^(@var{n}^2), so 16 for 2-by-2 and 512 for 3-by-3. +## +## makelut also passes parameters @var{P1}, @var{P2}, .... to @var{fun}. +## +## @end deftypefn +## @seealso{applylut} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function lut = makelut(fun, n, varargin) + if (nargin < 2) + usage ("lut = makelut(fun, n [, ...])"); + endif + + if (n<2) + error ("makelut: n should be a natural number >= 2"); + endif + + nq=n^2; + c=2^nq; + lut=zeros(c,1); + w=reshape(2.^[nq-1:-1:0],n,n); + for i=0:c-1 + idx=bitand(w,i)>0; + lut(i+1)= feval(fun, idx, all_va_args); + endfor +endfunction + +%!demo +%! makelut(inline('sum(x(:))>=3','x'), 2) +%! % Returns '1' if one or more values +%! % in the input matrix are 1 + +%!assert(prod(makelut(inline('sum(x(:))==2','x'),2)==makelut(inline('sum(x(:))==a*b*c*d','x','a','b','c','d'),2,2/(3*4*5),3,4,5))); # test multiple params +%!assert(prod(makelut(inline('x(1,1)==1','x'),2)==[zeros(2^3,1);ones(2^3,1)])==1); # test 2-by-2 +%!assert(prod(makelut(inline('x(1,1)==1','x'),3)==[zeros(2^8,1);ones(2^8,1)])==1); # test 3-by-3 +%!assert(prod(makelut(inline('x(1,1)==1','x'),4)==[zeros(2^15,1);ones(2^15,1)])==1); # test 4-by-4 +%!assert(prod(makelut(inline('x(2,1)==1','x'),3)==[zeros(2^7,1);ones(2^7,1);zeros(2^7,1);ones(2^7,1)])==1); # another test for 3-by-3 + + +
new file mode 100644 --- /dev/null +++ b/inst/mat2gray.m @@ -0,0 +1,49 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{I}= mat2gray (@var{M},[min max]) +## converts a matrix to a intensity image +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 22/03/2000 + +function I = mat2gray (M, scale) + + if (nargin < 1|| nargin > 2) + usage ("mat2gray(...) number of arguments must be 1 or 2"); + endif + + if (!is_matrix (M)) + usage ("mat2gray(M,...) M must be a matrix"); + endif + + if (nargin == 1) + Mmin = min (min (M)); + Mmax = max (max (M)); + else + if (isvector (scale)) + Mmin = min (scale (1), scale (2)); + Mmax = max (scale (1), scale (2)); + endif + endif + + I = (M < Mmin) .* 0; + I = I + (M >= Mmin & M < Mmax) .* (1 / (Mmax - Mmin) * (M - Mmin)); + I = I + (M >= Mmax); + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/mean2.m @@ -0,0 +1,39 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{m}= mean2 (@var{I}) +## returns the mean value for a 2d real type matrix. +## Uses @code{mean(I(:))} +## @end deftypefn +## @seealso{std2,mean} + + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 01/08/2000 + +function m = mean2 (I) + + if !(nargin == 1) + usage ("mean2(I)"); + endif + + if !(is_matrix(I) && isreal(I)) + error("argument must be a real type matrix"); + endif + + m = mean (I(:)); +endfunction
new file mode 100644 --- /dev/null +++ b/inst/medfilt2.m @@ -0,0 +1,68 @@ +## Copyright (C) 2000 Teemu Ikonen +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} medfilt2(@var{A}, [@var{domain}, @var{padding}]) +## Two dimensional median filtering. +## +## Replaces elements of @var{A} with the median of their neighbours defined +## by true elements of logical matrix @var{domain}. The default @var{domain} +## is a 3 by 3 matrix with all elements equal to 1. If @var{domain} is 1 by 2 +## row vector, the domain matrix will be +## logical(ones(@var{domain}(2), @var{domain}(1))). +## +## Optional variable @var{padding} defines the padding used in augmenting +## the borders of @var{A}. See impad for details. +## +## @end deftypefn +## @seealso{ordfilt2} + +## Author: Teemu Ikonen <tpikonen@pcu.helsinki.fi> +## Created: 5.5.2000 +## Keywords: image processing median filtering + +%!test +%! b = [0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18]; +%! assert(medfilt2(b),[0,1,2,0;1,4,12,3;4,12,20,12;0,7,20,0]); + +function retval = medfilt2(A, varargin) + +padding = "zeros"; +domain = logical(ones(3,3)); + +for i=1:length(varargin) + a = varargin{i}; + if(ischar(a)) + padding = a; + elseif(isvector(a) && size(a) == [1, 2]) + domain = logical(ones(a(2), a(1))); + elseif(is_matrix(a)) + domain = logical(a); + endif +endfor + +n = sum(sum(domain)); +if((n - 2*floor(n/2)) == 0) % n even - more work + nth = floor(n/2); + a = ordfilt2(A, nth, domain, padding); + b = ordfilt2(A, nth + 1, domain, padding); + retval = (a + b)./2; +else + nth = floor(n/2) + 1; + retval = ordfilt2(A, nth, domain, padding); +endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/nlfilter.m @@ -0,0 +1,170 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{B} = } nlfilter (@var{A}, [@var{m},@var{n}], @var{fun}) +## @deftypefnx {Function File} {@var{B} = } nlfilter (@var{A}, [@var{m},@var{n}], @var{fun}, ...) +## @deftypefnx {Function File} {@var{B} = } nlfilter (@var{A},'indexed', ...) +## Processes image in sliding blocks using user-supplied function +## +## @code{B=nlfilter(A,[m,n],fun)} passes sliding @var{m}-by-@var{n} +## blocks to user-supplied function @var{fun}. A block is build for +## every pixel in @var{A}, such as it is centered within the block. +## @var{fun} must return a scalar, and it is used to create matrix +## @var{B}. @var{nlfilter} pads the @var{m}-by-@var{n} block at the +## edges if necessary. +## +## Center of block is taken at ceil([@var{m},@var{n}]/2). +## +## @code{B=nlfilter(A,[m,n],fun,...)} behaves as described above but +## passes extra parameters to function @var{fun}. +## +## @code{B=nlfilter(A,'indexed',...)} assumes that @var{A} is an indexed +## image, so it pads the image using proper value: 0 for uint8 and +## uint16 images and 1 for double images. Keep in mind that if 'indexed' +## is not specified padding is always done using 0. +## +## @end deftypefn +## @seealso{colfilt,blkproc,inline} + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function B = nlfilter(A, varargin) + if(nargin<3) + error("nlfilter: invalid number of parameters."); + endif + + ## check 'indexed' presence + indexed=false; + p=1; + if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) + indexed=true; + p+=1; + if(isa(A,"uint8") || isa(A,"uint16")) + padval=0; + else + padval=1; + endif + else + padval=0; + endif + + ## check [m,n] + if(!isvector(varargin{p})) + error("nlfilter: expected [m,n] but param is not a vector."); + endif + if(length(varargin{p})!=2) + error("nlfilter: expected [m,n] but param has wrong length."); + endif + sblk=varargin{p}(:); + p+=1; + + ## check fun + ## TODO: add proper checks for this one + if(nargin<p) + error("nlfilter: required parameters haven't been supplied."); + endif + fun=varargin{p}; + + ## remaining params are params to fun + ## extra params are p+1:nargin-1 + + ## We take an easy approach... feel free to optimize it (coding this + ## in C++ would be a great idea). + + ## Calculate center of block + c=ceil(sblk/2); + + ## Pre-padding + prepad=c-ones(2,1); + + ## Post-padding + postpad=sblk-c; + + ## Save A size + as=size(A); + + ## Pad data + if(all(prepad==postpad)) + if(any(prepad>0)) + A=padarray(A,prepad,padval,'both'); + endif + else + if(any(prepad>0)) + A=padarray(A,prepad,padval,'pre'); + endif + if(any(postpad>0)) + A=padarray(A,postpad,padval,'post'); + endif + endif + + ## calc end offsets + me=postpad(1)+prepad(1); + ne=postpad(2)+prepad(2); + + ## We concatenate everything to preserve fun return type + for i=1:as(1) + r=feval(fun,A(i:i+me,1:1+ne),varargin{p+1:nargin-1}); + for j=2:as(2) + r=horzcat(r,feval(fun,A(i:i+me,j:j+ne),varargin{p+1:nargin-1})); + endfor + if(i==1) + B=r; + else + B=vertcat(B,r); + endif + endfor + +endfunction + +%!demo +%! nlfilter(eye(10),[3,3],inline("any(x(:)>0)","x")) +%! # creates a "wide" diagonal + +%!assert(nlfilter(eye(4),[2,3],inline("sum(x(:))","x")),[2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1]); +%!assert(nlfilter(eye(4),'indexed',[2,3],inline("sum(x(:))","x")),[4,2,1,2;3,2,2,3;2,1,2,4;4,3,4,5]); +%!assert(nlfilter(eye(4),'indexed',[2,3],inline("sum(x(:))==y","x","y"),2),[0,1,0,1;0,1,1,0;1,0,1,0;0,0,0,0]!=0); + +% Check uint8 and uint16 padding +%!assert(nlfilter(uint8(eye(4)),'indexed',[2,3],inline("sum(x(:))","x")),[2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1]); +%!assert(nlfilter(uint16(eye(4)),'indexed',[2,3],inline("sum(x(:))","x")),[2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1]); + +% Check if function class is preserved +%!assert(nlfilter(uint8(eye(4)),'indexed',[2,3],inline("int8(sum(x(:)))","x")),int8([2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1])); + + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.5 2005/09/08 02:00:17 pkienzle +% [for Bill Denney] isstr -> ischar +% +% Revision 1.4 2004/11/15 16:04:20 pkienzle +% Fix tests for functions which return boolean matrices +% +% Revision 1.3 2004/09/03 13:28:32 jmones +% Corrected behaviour for int* and uint* types +% +% Revision 1.2 2004/08/15 19:43:11 jmones +% corrected a typo in doc +% +% Revision 1.1 2004/08/15 19:42:14 jmones +% nlfilter: Processes image in siliding blocks using user-supplied function +% +%
new file mode 100644 --- /dev/null +++ b/inst/ordfilt2.m @@ -0,0 +1,72 @@ +## Copyright (C) 2000 Teemu Ikonen +## +## This program is free software; you can redistribute it and/or +## modify it under the terms of the GNU General Public License +## as published by the Free Software Foundation; either version 2 +## of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} ordfilt2(@var{A}, @var{nth}, @var{domain}, [@var{S}, @var{padding}]) +## Two dimensional ordered filtering. +## +## Ordered filter replaces an element of @var{A} with the @var{nth} +## element of the sorted set of neighbours defined by the logical +## (boolean) matrix @var{domain}. +## Neighbour elements are selected to the sort if the corresponding +## element in the @var{domain} matrix is true. +## +## The optional variable @var{S} is a matrix of size(@var{domain}). +## Values of @var{S} corresponding to nonzero values of domain are +## added to values obtained from @var{A} when doing the sorting. +## +## Optional variable @var{padding} determines how the matrix @var{A} +## is padded from the edges. See impad for details. +## +## @end deftypefn +## @seealso{medfilt2} + + +## Author: Teemu Ikonen <tpikonen@pcu.helsinki.fi> +## Created: 5.5.2000 +## Keywords: image processing filtering + +function retval = ordfilt2(A, nth, domain, varargin) + +S = zeros(size(domain)); +padding = "zeros"; +for i=1:length(varargin) + a = varargin{:}; + if(ischar(a)) + padding = a; + elseif(is_matrix(a) && size(a) == size(domain)) + S = a; + endif +endfor + +if(!islogical(domain)) + % warning("domain should be a boolean matrix, converting"); + domain = logical(domain); +endif; + +xpad(1) = floor((size(domain, 2)+1)/2) - 1; +xpad(2) = size(domain,2) - xpad(1) - 1; +ypad(1) = floor((size(domain, 1)+1)/2) - 1; +ypad(2) = size(domain,1) - ypad(1) - 1; + +if(ypad(1) >= size(A,1) || xpad(1) >= size(A,2)) + error("domain matrix too large"); +endif; + +A = impad(A, xpad, ypad, padding); +retval = cordflt2(A, nth, domain, S); + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/padarray.m @@ -0,0 +1,365 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{B} = } padarray (@var{A},@var{padsize}) +## @deftypefnx {Function File} {@var{B} = } padarray (@var{A},@var{padsize},@var{padval}) +## @deftypefnx {Function File} {@var{B} = } padarray (@var{A},@var{padsize},@var{padval},@var{direction}) +## Pads an array in a configurable way. +## +## B = padarray(A,padsize) pads an array @var{A} with zeros, where +## @var{padsize} defines the amount of padding to add in each dimension +## (it must be a vector of positive integers). +## +## Each component of @var{padsize} defines the number of elements of +## padding that will be added in the corresponding dimension. For +## instance, [4,5] adds 4 elements of padding in first dimension (vertical) +## and 5 in second dimension (horizontal). +## +## B = padarray(A,padsize,padval) pads @var{A} using the value specified +## by @var{padval}. @var{padval} can be a scalar or a string. Possible +## values are: +## @table @code +## @item 0 +## Pads with 0 as described above. This is the default behaviour. +## @item scalar +## Pads using @var{padval} as a padding value. +## @item 'circular' +## Pads with a circular repetition of elements in @var{A} (similar to +## tiling @var{A}). +## @item 'replicate' +## Pads 'replicating' values of @var{A} which are at the border of the +## array. +## @item 'symmetric' +## Pads with a mirror reflection of @var{A}. +## @end table +## +## B = padarray(A,padsize,padval,direction) pads @var{A} defining the +## direction of the pad. Possible values are: +## @table @code +## @item 'both' +## For each dimension it pads before the first element the number +## of elements defined by @var{padsize} and the same number again after +## the last element. This is the default value. +## @item 'pre' +## For each dimension it pads before the first element the number of +## elements defined by @var{padsize}. +## @item 'post' +## For each dimension it pads after the last element the number of +## elements defined by @var{padsize}. +## @end table +## @end deftypefn + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function B = padarray(A, padsize, padval, direction) + # Check parameters + if (nargin<2 || nargin>4) + usage ("B = padarray(A, padsize [, padval] [, direction])"); + endif + if (nargin<3) + padval=0; + endif + if (nargin<4) + direction='both'; + endif + + if (!isvector(padsize) || any(padsize<0)) + error("padarray: padsize must be a vector of positive integers."); + endif + + ## Assure padsize is a row vector + padsize=padsize(:).'; + + # Check direction + pre=false; + post=false; + switch(direction) + case('pre') + pre=true; + case('post') + post=true; + case('both') + post=true; + pre=true; + otherwise + error ("padarray: direction possible values are: 'pre', 'post' and 'both'"); + endswitch + + + B=A; + dim=1; + for s=padsize + if (s>0) + # padding in this dimension was requested + ds=size(B); + ds=[ds, ones(1,dim-length(ds))]; # data size + ps=ds; + ps(dim)=s; # padding size + + if (ischar(padval)) + # Init a "index all" cell array. All cases need it. + idx=cell(); + for i=1:length(ds) + idx{i}=1:ds(i); + endfor + + switch(padval) + case('circular') + complete=0; + D=B; + if (ps(dim)>ds(dim)) + complete=floor(ps(dim)/ds(dim)); + ps(dim)=rem(ps(dim),ds(dim)); + endif + if (pre) + for i=1:complete + B=cat(dim,D,B); + endfor + idxt=idx; + idxt{dim}=ds(dim)-ps(dim)+1:ds(dim); + B=cat(dim,D(idxt{:}),B); + endif + if (post) + for i=1:complete + B=cat(dim,B,D); + endfor + idxt=idx; + idxt{dim}=1:ps(dim); + B=cat(dim,B,D(idxt{:})); + endif + # end circular case + + case('replicate') + if (pre) + idxt=idx; + idxt{dim}=1; + pad=B(idxt{:}); + # can we do this without the loop? + for i=1:s + B=cat(dim,pad,B); + endfor + endif + if (post) + idxt=idx; + idxt{dim}=size(B,dim); + pad=B(idxt{:}); + for i=1:s + B=cat(dim,B,pad); + endfor + endif + # end replicate case + + case('symmetric') + if (ps(dim)>ds(dim)) + error("padarray: padding is longer than data using symmetric padding"); + endif + if (pre) + idxt=idx; + idxt{dim}=ps(dim):-1:1; + B=cat(dim,B(idxt{:}),B); + endif + if (post) + idxt=idx; + sbd=size(B,dim); + idxt{dim}=sbd:-1:sbd-ps(dim)+1; + B=cat(dim,B,B(idxt{:})); + endif + # end symmetric case + + otherwise + error("padarray: invalid string in padval parameter."); + + endswitch + # end cases where padval is a string + + elseif (isscalar(padval)) + # Handle fixed value padding + if (padval==0) + pad=zeros(ps,class(A)); ## class(pad) = class(A) + else + pad=padval*ones(ps,class(A)); ## class(pad) = class(A) + endif + if(pre&&post) + # check if this is not quicker than just 2 calls (one for each) + B=cat(dim,pad,B,pad); + elseif(pre) + B=cat(dim,pad,B); + elseif(post) + B=cat(dim,B,pad); + endif + else + error ("padarray: padval can only be a scalar or a string."); + endif + endif + dim+=1; + endfor +endfunction + +%!demo +%! padarray([1,2,3;4,5,6],[2,1]) +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 0 + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],5) +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 5 + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],0,'pre') +%! % pads [1,2,3;4,5,6] with a left and top border of 2 rows and 1 columns of 0 + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],'circular') +%! % pads [1,2,3;4,5,6] with a whole 'circular' border of 2 rows and 1 columns +%! % border 'repeats' data as if we tiled blocks of data + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],'replicate') +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which +%! % 'replicates' edge data + +%!demo +%! padarray([1,2,3;4,5,6],[2,1],'symmetric') +%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which +%! % is symmetric to the data on the edge + +% Test default padval and direction +%!assert(padarray([1;2],[1]), [0;1;2;0]); +%!assert(padarray([3,4],[0,2]), [0,0,3,4,0,0]); +%!assert(padarray([1,2,3;4,5,6],[1,2]), \ +%! [zeros(1,7);0,0,1,2,3,0,0;0,0,4,5,6,0,0;zeros(1,7)]); + +% Test padding on 3D array +%!test +%! int8(0); % fail for octave <= 2.1.57 without crashing +%! assert(padarray([1,2,3;4,5,6],[3,2,1]), cat(3, \ +%! zeros(8,7), \ +%! [zeros(3,7); [zeros(2,2), [1,2,3;4,5,6], zeros(2,2)]; zeros(3,7)], \ +%! zeros(8,7))); + +% Test if default param are ok +%!assert(padarray([1,2],[4,5])==padarray([1,2],[4,5],0)); +%!assert(padarray([1,2],[4,5])==padarray([1,2],[4,5],0,'both')); + +% Test literal padval +%!assert(padarray([1;2],[1],i), [i;1;2;i]); + +% Test directions (horizontal) +%!assert(padarray([1;2],[1],i,'pre'), [i;1;2]); +%!assert(padarray([1;2],[1],i,'post'), [1;2;i]); +%!assert(padarray([1;2],[1],i,'both'), [i;1;2;i]); + +% Test directions (vertical) +%!assert(padarray([1,2],[0,1],i,'pre'), [i,1,2]); +%!assert(padarray([1,2],[0,1],i,'post'), [1,2,i]); +%!assert(padarray([1,2],[0,1],i,'both'), [i,1,2,i]); + +% Test vertical padsize +%!assert(padarray([1,2],[0;1],i,'both'), [i,1,2,i]); + +% Test circular padding +%!test +%! A=[1,2,3;4,5,6]; +%! B=repmat(A,7,9); +%! assert(padarray(A,[1,2],'circular','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'circular','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'circular','both'), B(2:5,2:8)); +%! % This tests when padding is bigger than data +%! assert(padarray(A,[5,10],'circular','both'), B(2:13,3:25)); + +% Test replicate padding +%!test +%! A=[1,2;3,4]; +%! B=kron(A,ones(10,5)); +%! assert(padarray(A,[9,4],'replicate','pre'), B(1:11,1:6)); +%! assert(padarray(A,[9,4],'replicate','post'), B(10:20,5:10)); +%! assert(padarray(A,[9,4],'replicate','both'), B); + +% Test symmetric padding +%!test +%! A=[1:3;4:6]; +%! HA=[3:-1:1;6:-1:4]; +%! VA=[4:6;1:3]; +%! VHA=[6:-1:4;3:-1:1]; +%! B=[VHA,VA,VHA; HA,A,HA; VHA,VA,VHA]; +%! assert(padarray(A,[1,2],'symmetric','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'symmetric','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'symmetric','both'), B(2:5,2:8)); + +% Repeat some tests with int* uint* class types +%!assert(padarray(int8([1;2]),[1]), int8([0;1;2;0])); +%!assert(padarray(uint8([3,4]),[0,2]), uint8([0,0,3,4,0,0])); +%!assert(padarray(int16([1;2]),[1],4), int16([4;1;2;4])); +%!assert(padarray(uint16([1;2]),[1],0), uint16([0;1;2;0])); +%!assert(padarray(int32([1;2]),[1],int32(4),'pre'), int32([4;1;2])); +%!assert(padarray(uint32([1;2]),[1],6,'post'), uint32([1;2;6])); + +% Test circular padding with int* uint* class types +%!test +%! A=int8([1,2,3;4,5,6]); +%! B=repmat(A,7,9); +%! assert(padarray(A,[1,2],'circular','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'circular','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'circular','both'), B(2:5,2:8)); +%! % This tests when padding is bigger than data +%! assert(padarray(A,[5,10],'circular','both'), B(2:13,3:25)); + +% Test replicate padding with int* uint* class types +%!test +%! A=uint8([1,2;3,4]); +%! B=[ones(10,5,"uint8")*1,ones(10,5,"uint8")*2; \ +%! ones(10,5,"uint8")*3,ones(10,5,"uint8")*4]; +%! assert(padarray(A,[9,4],'replicate','pre'), B(1:11,1:6)); +%! assert(padarray(A,[9,4],'replicate','post'), B(10:20,5:10)); +%! assert(padarray(A,[9,4],'replicate','both'), B); + +% Test symmetric padding with int* uint* class types +%!test +%! A=int16([1:3;4:6]); +%! HA=int16([3:-1:1;6:-1:4]); +%! VA=int16([4:6;1:3]); +%! VHA=int16([6:-1:4;3:-1:1]); +%! B=[VHA,VA,VHA; HA,A,HA; VHA,VA,VHA]; +%! assert(padarray(A,[1,2],'symmetric','pre'), B(2:4,2:6)); +%! assert(padarray(A,[1,2],'symmetric','post'), B(3:5,4:8)); +%! assert(padarray(A,[1,2],'symmetric','both'), B(2:5,2:8)); + + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.6 2005/09/08 02:00:17 pkienzle +% [for Bill Denney] isstr -> ischar +% +% Revision 1.5 2004/09/03 18:33:11 pkienzle +% skip tests which use cat(3,X,Y) for octave <= 2.1.57 +% +% Revision 1.4 2004/09/03 13:37:10 jmones +% Corrected behaviour for int* and uint* types +% +% Revision 1.3 2004/08/15 19:21:50 jmones +% support column vector padsize +% +% Revision 1.2 2004/08/11 15:04:59 pkienzle +% Convert dos line endings to unix line endings +% +% Revision 1.1 2004/08/08 21:20:25 jmones +% uintlut and padarray functions added +% +%
new file mode 100644 --- /dev/null +++ b/inst/pink.m @@ -0,0 +1,55 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} pink (@var{n}) +## Create color colormap. +## (gives a sephia tone on b/w images) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = pink (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("pink: argument must be a scalar"); + endif + else + usage ("pink (number)"); + endif + + if (number == 1) + map = [0, 0, 0]; + elseif (number > 1) + x = linspace (0, 1, number)'; + r = (x < 3/8) .* (14/9 * x) + (x >= 3/8) .* (2/3 * x + 1/3); + g = (x < 3/8) .* (2/3 * x)\ + + (x >= 3/8 & x < 3/4) .* (14/9 * x - 1/3)\ + + (x >= 3/4) .* (2/3 * x + 1/3); + b = (x < 3/4) .* (2/3 * x) + (x >= 3/4) .* (2 * x - 1); + + map = sqrt ([r, g, b]); + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/poly2mask.m @@ -0,0 +1,256 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{BW} = } poly2mask (@var{x},@var{y},@var{m},@var{n}) +## Convert a polygon to a region mask +## +## BW=poly2mask(x,y,m,n) converts a polygon, specified by a list of +## vertices in @var{x} and @var{y} and returns in a @var{m}-by-@var{n} +## logical mask @var{BW} the filled polygon. Region inside the polygon +## is set to 1, values outside the shape are set to 0. +## +## @var{x} and @var{y} should always represent a closed polygon, first +## and last points should be coincident. If they are not poly2mask will +## close it for you. If @var{x} or @var{y} are fractional they are +## nearest integer. +## +## If all the polygon or part of it falls outside the masking area +## (1:m,1:n), it is discarded or clipped. +## +## This function uses scan-line polygon filling algorithm as described +## in http://www.cs.rit.edu/~icss571/filling/ with some minor +## modifications: capability of clipping and scan order, which can +## affect the results of the algorithm (algorithm is described not to +## reach ymax, xmax border when filling to avoid enlarging shapes). In +## this function we scan the image backwards (we begin at ymax and end +## at ymin), and we don't reach ymin, xmin, which we believe should be +## compatible with MATLAB. +## @end deftypefn + + +## TODO: check how to create a logical BW without any conversion + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function BW = poly2mask(x, y, m, n) + if (nargin!=4) + usage("BW = poly2mask(x, y, m, n)"); + endif + + ## check x and y + x=round(x(:)'); + y=round(y(:)'); + if(length(x)<3) + error("poly2mask: polygon must have at least 3 vertices."); + endif + if(length(x)!=length(y)) + error("poly2mask: length of x doesn't match length of y."); + endif + + ## create output matrix + uint8(0); ## This fails for octave < 2.1.58 + BW=logical(zeros(m,n,"uint8")); + + ## close polygon if needed + if((x(1)!=x(length(x)))||(y(1)!=y(length(y)))) + x=horzcat(x,x(1)); + y=horzcat(y,y(1)); + endif + + ## build global edge table + ex=[x(1:length(x)-1);x(1,2:length(x))]; ## x values for each edge + ey=[y(1:length(y)-1);y(1,2:length(y))]; ## y values for each edge + idx=find(ey(1,:)!=ey(2,:)); ## eliminate horizontal edges + ex=ex(:,idx); + ey=ey(:,idx); + eminy=min(ey); ## minimum y for each edge + emaxy=max(ey); ## maximum y for each edge + t=ey==[eminy;eminy]; ## values associated to miny + exminy=ex(:)(find(t)); ## x values associated to min y + exmaxy=ex(:)(find(!t)); ## x values associated to max y + emaxy=emaxy'; ## we want them vertical now... + eminy=eminy'; + m_inv=(exmaxy-exminy)./(emaxy-eminy); ## calculate inverse slope + ge=[emaxy, eminy, exmaxy, m_inv]; ## build global edge table + ge=sortrows(ge,[1,3]); ## sort on eminy and exminy + + ## we add an extra dummy edge at the end just to avoid checking + ## while indexing it + ge=[-Inf,-Inf,-Inf,-Inf;ge]; + + ## initial parity is even (0) + parity=0; + + ## init scan line set to bottom line + sl=ge(size(ge,1),1); + + ## init active edge table + ## we use a loop because the table is sorted and edge list could be + ## huge + ae=[]; + gei=size(ge,1); + while sl==ge(gei,1) + ae=[ge(gei,2:4);ae]; + gei-=1; + endwhile + + ## calc minimum y to draw + miny=min(y); + if (miny<1) + miny=1; + endif + + while sl>=miny + ## check vert clipping + if(sl<=m) + ## draw current scan line + ## we have to round because 1/m is fractional + ie=round(reshape(ae(:,2),2,size(ae)/2)); + + ## this discards left border of image (this differs from version at + ## http://www.cs.rit.edu/~icss571/filling/ which discards right + ## border) but keeps an exception when the point is a vertex. + ie(1,:)+=ie(1,:)!=ie(2,:); + + ## we'll clip too, just in case m,n is not big enough + ie(1,find(ie(1,:)<1))=1; + ie(2,find(ie(2,:)>n))=n; + + ## we eliminate segments outside window + ie=ie(:,find(ie(1,:)<=n)); + ie=ie(:,find(ie(2,:)>=1)); + for i=1:columns(ie) + BW(sl,ie(1,i):ie(2,i))=true; + endfor + endif + + ## decrement scan line + sl-=1; + + ## eliminate edges that eymax==sl + ## this discards ymin border of image (this differs from version at + ## http://www.cs.rit.edu/~icss571/filling/ which discards ymax). + ae=ae(find(ae(:,1)!=sl),:); + + ## update x (x1=x0-1/m) + ae(:,2)-=ae(:,3); + + ## update ae with new values + while sl==ge(gei,1) + ae=vertcat(ae,ge(gei,2:4)); + gei-=1; + endwhile + + ## order the edges in ae by x value + if(rows(ae)>0) + ae=sortrows(ae,2); + endif + endwhile +endfunction + + +%!demo +%! s=[0:pi/4:2*pi]; +%! x=cos(s)*90+101; +%! y=sin(s)*90+101; +%! bw=poly2mask(x,y,200,200); +%! imshow(bw); +%! %Creates a filled octagon + +%!demo +%! s=[0:2*pi/5:pi*4]; +%! s=s([1,3,5,2,4,6]); +%! x=cos(s)*90+101; +%! y=sin(s)*90+101; +%! bw=poly2mask(x,y,200,200); +%! imshow(bw); +%! %Creates a 5-vertex star + +%!# Convex polygons + +%!shared xs, ys, Rs, xt, yt, Rt +%! xs=[3,3,10,10]; +%! ys=[4,12,12,4]; +%! Rs=zeros(16,14); +%! Rs(5:12,4:10)=1; +%! Rs=logical(Rs); +%! xt=[1,4,7]; +%! yt=[1,4,1]; +%! Rt=[0,0,0,0,0,0,0; +%! 0,0,1,1,1,1,0; +%! 0,0,0,1,1,0,0; +%! 0,0,0,1,0,0,0; +%! 0,0,0,0,0,0,0]; +%! Rt=logical(Rt); + +%!assert(poly2mask(xs,ys,16,14),Rs); # rectangle +%!assert(poly2mask(xs,ys,8,7),Rs(1:8,1:7)); # clipped +%!assert(poly2mask(xs-7,ys-8,8,7),Rs(9:16,8:14)); # more clipping + +%!assert(poly2mask(xt,yt,5,7),Rt); # triangle +%!assert(poly2mask(xt,yt,3,3),Rt(1:3,1:3)); # clipped + + +%!# Concave polygons + +%!test +%! x=[3,3,5,5,8,8,10,10]; +%! y=[4,12,12,8,8,11,11,4]; +%! R=zeros(16,14); +%! R(5:12,4:5)=1; +%! R(5:8,6:8)=1; +%! R(5:11,9:10)=1; +%! R=logical(R); +%! assert(poly2mask(x,y,16,14), R); + +%!# Complex polygons +%!test +%! x=[1,5,1,5]; +%! y=[1,1,4,4]; +%! R=[0,0,0,0,0,0; +%! 0,0,1,1,0,0; +%! 0,0,1,1,0,0; +%! 0,1,1,1,1,0; +%! 0,0,0,0,0,0]; +%! R=logical(R); +%! assert(poly2mask(x,y,5,6), R); + + + + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.5 2004/09/07 14:47:50 pkienzle +% Avoid segfaults on pre-2.1.58 octave. Invisible whitespace changes. +% +% Revision 1.4 2004/09/03 17:12:36 jmones +% Uses uint8 to save some temporal memory (suggested by David Bateman) +% +% Revision 1.3 2004/09/03 13:32:07 jmones +% Work with logical arrays from BW creation +% +% Revision 1.2 2004/08/11 17:39:51 jmones +% Algorithm url in docs corrected. +% +% Revision 1.1 2004/08/11 17:34:11 jmones +% poly2mask added: creates filled polygon bw mask +% +%
new file mode 100644 --- /dev/null +++ b/inst/prism.m @@ -0,0 +1,48 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} prism (@var{n}) +## Create color colormap. +## (cycling trough red, orange, yellow, green, blue and violet) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = prism (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("prism: argument must be a scalar"); + endif + else + usage ("prism (number)"); + endif + + p = [1, 0, 0; 1, 1/2, 0; 1, 1, 0; 0, 1, 0; 0, 0, 1; 2/3, 0, 1]; + + if (rem (number, 6) == 0) + map = kron(ones (fix (number / 6), 1), p); + else + map = [kron(ones (fix (number / 6), 1), p); p(1:rem (number, 6), :)]; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/qtdecomp.m @@ -0,0 +1,331 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{S} = } qtdecomp (@var{I}) +## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{threshold}) +## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{threshold},@var{mindim}) +## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{threshold},@var{[mindim maxdim]}) +## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{fun}) +## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{fun},@var{P1},@var{P2},...) +## Performs quadtree decomposition +## +## qtdecomp decomposes a square image @var{I} into four equal-sized +## blocks. Then it performs some kind of test on each block to decide if +## it should decompose them further. This process is repeated +## iteratively until there's no block left to be decomposed. +## +## Note that blocks are not decomposed if their dimensions are not even. +## +## The output is a sparse matrix whose non-zero elements determine the +## position of the block (the element is at top-left position in the +## block) and size of each block (the value of the element determines +## length of a side of the square-shaped block). +## +## S = qtdecomp(I) decomposes an intensity image @var{I} as described +## above. By default it doesn't split a block if all elements are equal. +## +## S = qtdecomp(I, threshold) decomposes an image as decribed, but only +## splits a block if the maximum value in the block minus the minimum +## value is greater than @var{threshold}, which is a value between 0 and +## 1. If @var{I} is of class uint8, @var{threshold} is multiplied by 255 +## before use. Also, if@var{I} is of class uint16, @var{threshold} is +## multiplied by 65535. +## +## S = qtdecomp(I, threshold, mindim) decomposes an image using the +## @var{threshold} as just described, but doesn't produce blocks smaller +## than mindim. +## +## S = qtdecomp(I, threshold, [mindim maxdim]) decomposes an image as +## described, but produces blocks that can't be bigger than maxdim. It +## decomposes to maxdim even if it isn't needed if only @var{threshold} +## was considered. +## +## S = qtdecomp(I, fun) decomposes an image @var{I} and uses function +## @var{fun} to decide if a block should be splitted or not. @var{fun} +## is called with a m-by-m-by-k array of m-by-m blocks to be +## considered, and should return a vector of size k, whose elements +## represent each block in the stacked array. @var{fun} sets the +## corresponding value to 1 if the block should be split, and 0 +## otherwise. +## +## S = qtdecomp(I, fun, ...) behaves as qtdecomp(I, fun) but passes +## extra parameters to @var{fun}. +## +## @end deftypefn +## @seealso qtgetblk, qtsetblk + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function S = qtdecomp(I, p1, varargin) + if (nargin<1) + usage("S=qtdecomp(I)"); + endif + + if (!ismatrix(I) || size(I,1)!=size(I,2)) + error("qtdecomp: I should be a square matrix."); + endif + + ## current size (assumed to be square) + curr_size=size(I,1); + + ## initial mindim to a sensible value + mindim=1; + + ## sensible default maxdim value + maxdim=curr_size; + + if (nargin<2) + ## Initialize decision method variable + ## We could have implemented threshold as a function and use an + ## uniform interface (function handle) to decide whether to split or + ## not blocks. We have decided not to do so because block + ## rearrangement that is needed as a parameter to functions is + ## expensive. + decision_method=0; + elseif (isreal(p1)) + ## p1 is threshold + threshold=p1; + decision_method=1; + + if(strcmp(typeinfo(I), 'uint8 matrix')) + threshold*=255; + elseif(strcmp(typeinfo(I), 'uint16 matrix')) + threshold*=65535; + endif + + if (nargin>3) + usage("S=qtdecomp(I,threshold,mindim), \ + S=qtdecomp(I,threshold,[mindim maxdim])"); + elseif (nargin==3) + dims=varargin{1}; + if (isvector(dims)&&length(dims)==2) + mindim=dims(1); + maxdim=dims(2); + elseif (isreal(dims)) + mindim=dims; + else + error("qtdecomp: third parameter must be 'mindim' or '[mindim maxdim]'"); + endif + ## we won't check if mindim or maxdim are powers of 2. It's too + ## restrictive and don't need it at all. + endif + + elseif strcmp(typeinfo(p1),"function handle") ... + || strcmp(typeinfo(p1),"inline function") + ## function handles seem to return true to isscalar + fun=p1; + decision_method=2; + else + error("qtdecomp: second parameter must be a integer (threshold) or a function handle (fun)."); + endif + + ## initialize results matrices + res=[]; + + ## bool to flag end + finished=false; + + ## array of offsets to blocks to evaluate + offsets=[1,1]; + + if (maxdim<mindim) + error("qtdecomp: mindim must be smaller than maxdim."); + endif + + ## See if we have to split a minimum regarless other considerations. + if (maxdim<curr_size) + initial_splits=ceil(log2(curr_size/maxdim)); + if(initial_splits>0) + divs=2^initial_splits; + if (rem(curr_size,divs)!=0) + error("qtdecomp: Can't decompose I enough times to fulfill maxdim requirement."); + endif + ## update curr_size + curr_size/=divs; + if(curr_size<mindim) + error("qtdecomp: maxdim restriction collides with mindim restriction."); + endif + els=transpose([0:divs-1]*curr_size+1); + offsets=[kron(els,ones(divs,1)), kron(ones(divs,1),els)]; + endif + endif + + while(!finished && rows(offsets)>0) + ## check other ending conditions: + ## is size is odd? + ## is splitted size < than mindim? + if ((rem(curr_size,2)!=0)||((curr_size/2)<mindim)) + ## can't continue, lets add current evaluation blocks to results + res=[res; offsets, ones(size(offsets,1),1)*curr_size]; + finished = true; + else + if (decision_method<2) + db=logical(ones(rows(offsets),1)); + for r=1:rows(offsets) + o=offsets(r,:); + fo=offsets(r,:)+curr_size-1; + + if(decision_method==0) + ## is everything equal? + if (all(I(o(1),o(2))==I(o(1):fo(1),o(2):fo(2)))) + db(r)=0; + endif + else + ## check threshold + t=I(o(1):fo(1),o(2):fo(2)); + t=t(:); + if ((max(t)-min(t))<=threshold) + db(r)=0; + endif + endif + endfor + elseif(decision_method==2) + ## function handle decision method + ## build blocks + b=zeros(curr_size,curr_size,rows(offsets)); + rbc=offsets(:,1:2)+curr_size-1; + for r=1:rows(offsets) + b(:,:,r)=I(offsets(r,1):rbc(r,1),offsets(r,2):rbc(r,2)); + endfor + + db=feval(fun, b, varargin{:}); + else + error("qtdecomp: execution shouldn't reach here. Please report this as a bug."); + endif + + ## Add blocks that won't divide to results + nd=offsets(find(!db),:); + res=[res; nd, ones(size(nd,1),1)*curr_size]; + + ## Update curr_size for next iteration + curr_size/=2; + + ## Prepare offsets for next iteration + otemp=offsets(find(db),:); + hs=ones(rows(otemp),1)*curr_size; + zs=zeros(size(hs)); + offsets=[otemp;otemp+[hs,zs];otemp+[zs,hs];otemp+[hs,hs]]; + endif + endwhile + + S=sparse(res(:,1),res(:,2),res(:,3),size(I,1),size(I,2)); +endfunction + + +%!demo +%! full(qtdecomp(eye(8))) +%! %It finds 2 big blocks of 0 and it decomposes further where 0 and 1 are mixed. + + +%!# Test if odd-sized limits split +%!assert(full(qtdecomp(eye(5))), reshape([5,zeros(1,24)],5,5)); +%!assert(full(qtdecomp(eye(6))), repmat(reshape([3,zeros(1,8)],3,3),2,2)); + +%!# Test 'equal' method +%!test +%! a=ones(2,2); +%! b=[2,0;0,0]; +%! assert(full(qtdecomp(eye(4))), [a,b;b,a]); + +%!shared A, B2, B4 +%! A=[ 1, 4, 2, 5,54,55,61,62; +%! 3, 6, 3, 1,58,53,67,65; +%! 3, 6, 3, 1,58,53,67,65; +%! 3, 6, 3, 1,58,53,67,65; +%! 23,42,42,42,99,99,99,99; +%! 27,42,42,42,99,99,99,99; +%! 23,22,26,25,99,99,99,99; +%! 22,22,24,22,99,99,99,99]; +%! B2=[2,0;0,0]; +%! B4=zeros(4); B4(1,1)=4; + +%!test +%! R=[ones(4,8); [ones(2),B2;ones(2,4)], B4]; +%! assert(full(qtdecomp(A)), R); +%! assert(full(qtdecomp(A,0)), R); + +%!# Test 'threshold' method +%!test +%! R=[ones(4,8); [ones(2),B2;B2,ones(2)],B4]; +%! assert(full(qtdecomp(A,1)), R); + +%!test +%! R=[[B4,[B2,B2;B2,B2]]; [[ones(2),B2;B2,B2],B4]]; +%! assert(full(qtdecomp(A,10)), R); + +%!test +%! R=[[B4,[B2,B2;B2,B2]]; [[B2,B2;B2,B2],B4]]; +%! assert(full(qtdecomp(A,10,2)), R); + +%!assert(full(qtdecomp(A,100,[2, 4])), [B4,B4;B4,B4]); + +%!# Test 'fun' method +%!# Can't define a function inside tests because Octave +%!# complains about nested functions. If you know how to +%!# do it please add function handle tests. + +%!# inline version +%!# We use [size(A),1](3) as a trick since size(A,3) fails if A is 2D. + +%!# no params +%!test +%! first_eq=inline("(A(1,1,:)!=(54*ones(1,1,[size(A),1](3))))(:)","A"); +%! assert(full(qtdecomp(A,first_eq)),[ones(4),B4;ones(4,8)]); + +%!# 1 param +%!test +%! first_eq=inline("(A(1,1,:)!=(c*ones(1,1,[size(A),1](3))))(:)","A","c"); +%! assert(full(qtdecomp(A,first_eq,54)),[ones(4),B4;ones(4,8)]); + +%!# 3 params +%!test +%! first_eq=inline("(A(1,1,:)!=((c1+c2+c3)*ones(1,1,[size(A),1](3))))(:)","A","c1","c2","c3"); +%! assert(full(qtdecomp(A,first_eq,4,40,10)),[ones(4),B4;ones(4,8)]); + + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.8 2006/01/03 02:09:15 pkienzle +% Reorder tests so that shared variables are displayed unless relevant. +% +% Revision 1.7 2006/01/02 22:05:06 pkienzle +% Reduce number of shared variables in tests +% +% Revision 1.6 2004/09/09 19:36:35 jmones +% all_va_args -> varargin{:}. Now works on 2.1.58 +% +% Revision 1.5 2004/09/08 14:07:22 pkienzle +% Fix test for 'inline function' +% +% Revision 1.4 2004/08/11 19:52:41 jmones +% qtsetblk added +% +% Revision 1.3 2004/08/11 00:05:21 jmones +% seealso qtgetblk added to doc +% +% Revision 1.2 2004/08/10 00:19:42 jmones +% Corrected misleading comment. +% +% Revision 1.1 2004/08/09 01:48:54 jmones +% Added qtdecomp: quadtree decomposition +% +% +
new file mode 100644 --- /dev/null +++ b/inst/qtgetblk.m @@ -0,0 +1,154 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{vals}] = } qtgetblk (@var{I},@var{S},@var{dim}) +## @deftypefnx {Function File} {[@var{vals},@var{idx}] = } qtgetblk (@var{I},@var{S},@var{dim}) +## @deftypefnx {Function File} {[@var{vals},@var{r},@var{c}] = } qtgetblk (@var{I},@var{S},@var{dim}) +## Obtain block values from a quadtree decomposition +## +## [vals]=qtgetblk(I,S,dim) returns a dim-by-dim-by-k array in +## @var{vals} which contains the dim-by-dim blocks in the quadtree +## decomposition (@var{S}, which is returned by qtdecomp) of @var{I}. If +## there are no blocks, an empty matrix is returned. +## +## [vals,idx]=qtgetblk(I,S,dim) returns @var{vals} as described above. +## In addition, it returns @var{idx}, a vector which contains the linear +## indices of the upper left corner of each block returned (the same +## result as find(full(S)==dim)). +## +## [vals,r,c]=qtgetblk(I,S,dim) returns @var{vals} as described, and two +## vectors, @var{r} and @var{c}, which contain the row and column +## coordinates of the blocks returned. +## +## @end deftypefn +## @seealso qtdecomp, qtsetblk + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function [varargout] = qtgetblk(I, S, dim) + if (nargin!=3) + usage("[vals,r,c]=qtgetblk(I,S,dim), [vals,idx]=qtgetblk(I,S,dim)"); + endif + if (nargout>3) + usage("[vals,r,c]=qtgetblk(I,S,dim), [vals,idx]=qtgetblk(I,S,dim)"); + endif + + ## get blocks + [i,j,v]=spfind(S); + + ## filter the ones which match dim + idx=find(v==dim); + + if(length(idx)==0) + for i=1:nargout + varargout{i}=[]; + endfor + else + r=i(idx); + c=j(idx); + + ## copy to a dim-by-dim-by-k array + vals=zeros(dim,dim,length(idx)); + for i=1:length(idx) + vals(:,:,i)=I(r(i):r(i)+dim-1,c(i):c(i)+dim-1); + endfor + + varargout{1}=vals; + + if(nargout==3) + varargout{2}=r; + varargout{3}=c; + elseif(nargout==2) + varargout{2}=(c-1)*rows(I)+r; + endif + endif +endfunction + + +%!demo +%! [vals,r,c]=qtgetblk(eye(4),qtdecomp(eye(4)),2) +%! % Returns 2 blocks, at [1,3] and [3,1] (2*2 zeros blocks) + +%!shared A,S +%! A=[ 1, 4, 2, 5,54,55,61,62; +%! 3, 6, 3, 1,58,53,67,65; +%! 3, 6, 3, 1,58,53,67,65; +%! 3, 6, 3, 1,58,53,67,65; +%! 23,42,42,42,99,99,99,99; +%! 27,42,42,42,99,99,99,99; +%! 23,22,26,25,99,99,99,99; +%! 22,22,24,22,99,99,99,99]; +%! S=qtdecomp(A,10); + +%!test +%! [va]=qtgetblk(A,S,8); +%! [vb,r,c]=qtgetblk(A,S,8); +%! [vc,i]=qtgetblk(A,S,8); +%! assert(va, vb); +%! assert(va, vc); +%! assert(i,[]); +%! assert(r,[]); +%! assert(c,[]); +%! R=[]; +%! assert(va,R); + + +%!test +%! [va]=qtgetblk(A,S,4); +%! [vb,r,c]=qtgetblk(A,S,4); +%! [vc,i]=qtgetblk(A,S,4); +%! assert(va, vb); +%! assert(va, vc); +%! assert(i, find(full(S)==4)); +%! assert(r,[1;5]); +%! assert(c,[1;5]); +%! R=zeros(4,4,2); +%! R(:,:,1)=A(1:4,1:4); +%! R(:,:,2)=A(5:8,5:8); +%! assert(va,R); + +%!test +%! [va]=qtgetblk(A,S,2); +%! [vb,r,c]=qtgetblk(A,S,2); +%! [vc,i]=qtgetblk(A,S,2); +%! assert(va, vb); +%! assert(va, vc); +%! assert(i, find(full(S)==2)); +%! assert(r,[7;5;7;1;3;1;3]); +%! assert(c,[1;3;3;5;5;7;7]); +%! R=zeros(2,2,7); +%! R(:,:,1)=A(7:8,1:2); +%! R(:,:,2)=A(5:6,3:4); +%! R(:,:,3)=A(7:8,3:4); +%! R(:,:,4)=A(1:2,5:6); +%! R(:,:,5)=A(3:4,5:6); +%! R(:,:,6)=A(1:2,7:8); +%! R(:,:,7)=A(3:4,7:8); +%! assert(va,R); + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.3 2006/01/02 20:53:42 pkienzle +% Reduce number of shared variables in tests +% +% Revision 1.2 2004/08/11 19:52:41 jmones +% qtsetblk added +% +%
new file mode 100644 --- /dev/null +++ b/inst/qtsetblk.m @@ -0,0 +1,105 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{J} = } qtsetblk (@var{I},@var{S},@var{dim},@var{vals}) +## Set block values in a quadtree decomposition +## +## J=qtsetblk(I,S,dim,vals) sets all the @var{dim}-by-@var{dim} blocks +## in the quadtree decomposition (@var{S} returned by qtdecomp) of +## @var{I} to @var{dim}-by-@var{dim} blocks in @var{vals}, which is +## itself a @var{dim}-by-@var{dim}-by-k array. k is the number of +## @var{dim}-by-@var{dim} blocks in the quadtree decomposition. +## @end deftypefn +## @seealso qtdecomp, qtgetblk + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function J = qtsetblk(I, S, dim, vals) + if (nargin!=4) + usage("J=qtsetblk(I,S,dim,vals)"); + endif + + ## get blocks + [ii,ji,v]=spfind(S); + + ## filter the ones which match dim + idx=find(v==dim); + if(size(vals,3)<length(idx)) ## we won't complain if k>num blocks + error("qtsetblk: k (vals 3rd dimension) is not equal to number of blocks."); + endif + ii=ii(idx); + ji=ji(idx); + + ## calc end vertex + ie=ii+dim-1; + je=ji+dim-1; + + + J=I; + for b=1:length(idx) + J(ii(b):ie(b),ji(b):je(b))=vals(:,:,b); + endfor +endfunction + + +%!demo +%! J=qtsetblk(eye(4),qtdecomp(eye(4)),2,ones(2,2,2)) +%! % Sets upper-right and lower-left blocks of 2*2 zeros to ones + +%!shared A, S +%! A=[ 1, 4, 2, 5,54,55,61,62; +%! 3, 6, 3, 1,58,53,67,65; +%! 3, 6, 3, 1,58,53,67,65; +%! 3, 6, 3, 1,58,53,67,65; +%! 23,42,42,42,99,99,99,99; +%! 27,42,42,42,99,99,99,99; +%! 23,22,26,25,99,99,99,99; +%! 22,22,24,22,99,99,99,99]; +%! S=qtdecomp(A,10); + +%!test +%! R=A; +%! vals=zeros(4,4,2); +%! vals(:,:,1)=reshape([1:16],4,4); +%! vals(:,:,2)=reshape([21:36],4,4); +%! R(1:4,1:4)=reshape([1:16],4,4); +%! R(5:8,5:8)=reshape([21:36],4,4); +%! assert(qtsetblk(A,S,4,vals),R); + +%!test +%! R=A; +%! R(1:4,5:8)=1; +%! R(7:8,1:4)=1; +%! R(5:6,3:4)=1; +%! assert(qtsetblk(A,S,2,ones(2,2,7)),R); + +%!test +%! R=A; +%! R(5:6,1:2)=10; +%! assert(qtsetblk(A,S,1,ones(1,1,4)*10),R); + + + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.1 2004/08/11 19:52:41 jmones +% qtsetblk added +% +%
new file mode 100644 --- /dev/null +++ b/inst/rainbow.m @@ -0,0 +1,56 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} rainbow (@var{n}) +## Create color colormap. +## (red through orange, yellow, green, blue to violet) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = rainbow (number) +## this colormap is not part of matlab, it is like the prism +## colormap map but with a continuous map + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("rainbow: argument must be a scalar"); + endif + else + usage ("rainbow (number)"); + endif + + if (number == 1) + map = [1, 0, 0]; + elseif (number > 1) + x = linspace (0, 1, number)'; + r = (x < 2/5) + (x >= 2/5 & x < 3/5) .* (-5 * x + 3)\ + + (x >= 4/5) .* (10/3 * x - 8/3); + g = (x < 2/5) .* (5/2 * x) + (x >= 2/5 & x < 3/5)\ + + (x >= 3/5 & x < 4/5) .* (-5 * x + 4); + b = (x >= 3/5 & x < 4/5) .* (5 * x - 3) + (x >= 4/5); + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/rgb2gray.m @@ -0,0 +1,47 @@ +## Copyright (C) 2000, 2001 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{I}= rgb2gray (@var{M}) +## converts a color map to a gray map. +## The RGB map is converted into the YIQ space of ntsc. The luminance +## value (Y) is taken to create a gray color map. +## R = G = B = Y +## @end deftypefn + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 19. March 2000 + +function graymap = rgb2gray (rgb) + + if (nargin != 1) + usage ("graymap = rgb2gray (map)"); + endif + + msg = "rgb2gray: argument must be a matrix of size n x 3"; + if (! is_matrix (rgb)) + error (msg); + endif + + nc = columns (rgb); + if (nc != 3) + error (msg); + endif + + ntscmap = rgb2ntsc (rgb); + + graymap = ntscmap (:, 1) * ones (1, 3); +endfunction
new file mode 100644 --- /dev/null +++ b/inst/roicolor.m @@ -0,0 +1,77 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{BW} = } roicolor (@var{A},@var{low},@var{high}) +## @deftypefnx {Function File} {@var{BW} = } roicolor (@var{A},@var{v}) +## Select a Region Of Interest of an image based on color. +## +## BW = roicolor(A,low,high) selects a region of interest (ROI) of an +## image @var{A} returning a black and white image in a logical array (1 for +## pixels inside ROI and 0 outside ROI), which is formed by all pixels +## whose values lie within the colormap range specified by [@var{low} +## @var{high}]. +## +## BW = roicolor(A,v) selects a region of interest (ROI) formed by all +## pixels that match values in @var{v}. +## @end deftypefn + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function BW = roicolor(A, p1, p2) + if (nargin < 2 || nargin > 3) + usage("BW = roicolor(A, low, high), BW = roicolor(A, v)"); + endif + + if (nargin == 2) + if (!isvector(p1)) + error("BW = roicolor(A, v): v should be a vector."); + endif + BW=logical(zeros(size(A))); + for c=p1 + BW|=(A==c); + endfor + elseif (nargin==3) + if (!isscalar(p1) || !isscalar(p2)) + error("BW = roicolor(A, low, high): low and high must be scalars."); + endif + BW=logical((A>=p1)&(A<=p2)); + endif +endfunction + +%!demo +%! roicolor([1:10],2,4); +%! % Returns '1' where input values are between 2 and 4 (both included). + +%!assert(roicolor([1:10],2,4),logical([0,1,1,1,zeros(1,6)])); +%!assert(roicolor([1,2;3,4],3,3),logical([0,0;1,0])); +%!assert(roicolor([1,2;3,4],[1,4]),logical([1,0;0,1])); + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:35 hauberg +% Changed the structure to match the package system +% +% Revision 1.3 2004/09/15 17:54:59 pkienzle +% test that data type matches during assert +% +% Revision 1.2 2004/08/11 15:04:59 pkienzle +% Convert dos line endings to unix line endings +% +% Revision 1.1 2004/08/08 21:02:44 jmones +% Add roicolor function (selects ROI based on color) +% +%
new file mode 100644 --- /dev/null +++ b/inst/spring.m @@ -0,0 +1,51 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} spring (@var{n}) +## Create color colormap. +## (magenta to yellow) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = spring (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("spring: argument must be a scalar"); + endif + else + usage ("spring (number)"); + endif + + if (number == 1) + map = [1, 0, 1]; + elseif (number > 1) + r = ones (number, 1); + g = (0:number - 1)' ./ (number - 1); + b = 1 - g; + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/std2.m @@ -0,0 +1,38 @@ +## Copyright (C) 2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} @var{s}= std2 (@var{I}) +## returns the standard deviation for a 2d real type matrix. +## Uses @code{std (I(:))} +## @end deftypefn +## @seealso{mean2,std} + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 01/08/2000 + +function s = std2 (I) + + if !(nargin == 1) + usage ("std2(I)"); + endif + + if !(is_matrix(I) && isreal(I)) + error("argument must be a real type matrix"); + endif + + s = std (I(:)); +endfunction
new file mode 100644 --- /dev/null +++ b/inst/stretchlim.m @@ -0,0 +1,209 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I},@var{TOL}) +## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I}) +## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB},@var{TOL}) +## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB}) +## Finds limits to contrast stretch an image +## +## @code{LOW_HIGH=stretchlim(I,TOL)} returns a vector @var{LOW_HIGH} +## which contains a pair of intensities which can be used in +## @code{imadjust} to stretch the contrast of an image, first of them +## will be lower value (@code{imadjust} would assign 0 to it) and second +## is the upper bound. @var{TOL} specifies the fraction of the image to +## saturate at lower and upper limits. It can be a vector of length 2: +## @code{[LOW_FRACT, HIGH_FRACT]}, or it can be a scalar, in that case +## @code{[LOW_FRACT, HIGH_FRACT]=[TOL, 1-TOL]}. +## +## @var{TOL} can't be larger than 0.50 and for TOL=0 then +## @code{LOW_HIGH=[min(I(:)), max(I(:))]}. +## +## @code{LOW_HIGH=stretchlim(I)} behaves as described but defaults +## @var{TOL} to @code{[0.01, 0.99]}. +## +## @code{LOW_HIGH=stretchlim(RGB,TOL)} returns a 2-by-3 matrix in +## @var{LOW_HIGH} of lower and upper values to saturate for each plane +## of the RGB image in M-by-N-by-3 array @var{RGB}. @var{TOL} is a +## vector or a scalar, as described above, and the same fractions are +## applied for each plane. +## +## @code{LOW_HIGH=stretchlim(RGB)} uses @code{[0.01, 0.99]} as default +## value for @var{TOL}. +## +## @strong{Notes:} +## +## Values in @var{LOW_HIGH} are of type double and comprised between 0 +## and 1 regardless class of input image. +## +## @strong{Compatibility notes:} +## +## @itemize @bullet +## @item +## int* and uint* types are still not implemented (waiting for support +## in Octave 2.1.58). +## @item +## This function tries to find limits that are nearer to saturate +## requested interval. So, for instance, if you requested a 5% and it +## has to choose between discarding a 1% and a 7%, it will choose the +## later despite being more than requested. This should be test against +## MATLAB behaviour. +## @end itemize +## +## @end deftypefn +## @seealso imadjust + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function LOW_HIGH = stretchlim(image, TOL) + if (nargin<1 || nargin>2) + usage("LOW_HIGH=stretchlim(I [, TOL]), LOW_HIGH=stretchlim(RGB [, TOL])"); + endif + + if(!ismatrix(image)) + error("stretchlim: image should be a matrix"); + endif + + ## Prepare limits + if(nargin==1) + low_count=0.01; + high_count=0.01; ## we use this definition in __stretchlim_plane__ + else + if(isscalar(TOL)) + if(TOL<0 || TOL>=0.5) + error("stretchlim: TOL out of bounds. Expected: 0<=TOL<0.5"); + endif + low_count=TOL; + high_count=TOL; ## as before... + elseif(isvector(TOL)) + if(length(TOL)!=2) + error("stretchlim: TOL length must be 2."); + endif + low_count=TOL(1); + high_count=1-TOL(2); ## as before... + else + error("stretchlim: TOL contains an invalid value."); + endif + endif + + ## well use size of image several times... + simage=size(image); + + ## Convert fractions to pixels + psimage=prod(simage(1:2)); + low_count*=psimage; + high_count*=psimage; + + if(length(simage)<=2) + ## intensity + LOW_HIGH=__stretchlim_plane__(image, low_count, high_count); + elseif(length(simage)==3 && simage(3)==3) + ## RGB + LOW_HIGH=zeros(2,3); + for i=1:3 + LOW_HIGH(:,i)=__stretchlim_plane__(image(:,:,i), low_count, \ + high_count); + endfor + else + error("stretchlim: invalid image."); + endif +endfunction + + +## Processes a plane +## high_count is defined so that high_count=elements is the same as +## low_count=elements (and not total_elements-elements) +function LOW_HIGH = __stretchlim_plane__(plane, low_count, high_count) + ## check exceptions + if(low_count==0 && high_count==0) + LOW_HIGH=[min(plane(:)); max(plane(:))]; + else + + ## we sort values + sorted=sort(plane(:)); + + low=sorted(round(low_count+1)); + pos=find(sorted>low); + if(length(pos)>0) + low2=sorted(pos(1)); + d1=low_count-sum(sorted<low); + d2=sum(sorted<low2)-low_count; + if(d2<d1) + low=low2; + endif + endif + + high=sorted(end-round(high_count)); + pos=find(sorted<high); + if(length(pos)>0) + high2=sorted(pos(end)); + d1=high_count-sum(sorted>high); + d2=sum(sorted>high2)-high_count; + if(d2<d1) + high=high2; + endif + endif + + ## set result variable + LOW_HIGH=[low;high]; + endif +endfunction + +%!demo +%! stretchlim([1:100]) +%! # This discards 1% of data from each end, 1 and 100. +%! # So result should be [2;99] + +%!# some invalid params +%!error(stretchlim()); +%!error(stretchlim("bad parameter")); +%!error(stretchlim(zeros(10,10,4))); +%!error(stretchlim(zeros(10,10,3,2))); +%!error(stretchlim(zeros(10,10),"bad parameter")); +%!error(stretchlim(zeros(10,10),0.01,2)); + + +%!# default param +%!assert(stretchlim([1:100]),[2;99]); + +%!# scalar TOL +%!assert(stretchlim([1:100],0.01),[2;99]); + +%!# vector TOL +%!assert(stretchlim([1:100],[0.01,0.98]),[2;98]); + +%!# TOL=0 +%!assert(stretchlim([1:100],0),[1;100]); + +%!# non uniform histogram tests +%!assert(stretchlim([1,ones(1,90)*2,92:100],0.05),[2;95]); +%!assert(stretchlim([1,ones(1,4)*2,6:100],0.05),[6;95]); + +%!# test limit rounding... +%!assert(stretchlim([1,ones(1,5)*2,7:100],0.05),[7;95]); # 6% lost +%!assert(stretchlim([1,ones(1,6)*2,8:100],0.05),[8;95]); # 7% lost +%!assert(stretchlim([1,ones(1,7)*2,9:100],0.05),[9;95]); # 8% lost +%!assert(stretchlim([1,ones(1,8)*2,10:100],0.05),[2;95]); # now he limit at 2 => 1% lost + +%!# test RGB +%!test +%! RGB=zeros(100,1,3); +%! RGB(:,:,1)=[1:100]; +%! RGB(:,:,2)=[2:2:200]; +%! RGB(:,:,3)=[4:4:400]; +%! assert(stretchlim(RGB),[2,4,8;99,198,396]); +
new file mode 100644 --- /dev/null +++ b/inst/summer.m @@ -0,0 +1,52 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} summer (@var{n}) +## Create color colormap. +## (green to yellow) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> +## Date: 06/03/2000 +function map = summer (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("summer: argument must be a scalar"); + endif + else + usage ("summer (number)"); + endif + + if (number == 1) + map = [0, 0.5, 0.4]; + elseif (number > 1) + r = (0:number - 1)' ./ (number - 1); + g = 0.5 + r ./ 2; + b = 0.4 * ones (number, 1); + + map = [r, g, b]; + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/testimio.m @@ -0,0 +1,56 @@ +## This program is public domain. + +## build image for image r/w tests +x=linspace(-8,8,200); +[xx,yy]=meshgrid(x,x); +r=sqrt(xx.^2+yy.^2) + eps; +map=colormap(hsv); +A=sin(r)./r; +minval = min(A(:)); +maxval = max(A(:)); +z = round ((A-minval)/(maxval - minval) * (rows(colormap) - 1)) + 1; +Rw=Gw=Bw=z; +Rw(:)=fix(255*map(z,1)); +Gw(:)=fix(255*map(z,2)); +Bw(:)=fix(255*map(z,3)); +Aw=fix(255*(1-r/max(r(:)))); ## Fade to nothing at the corners + +if exist("jpgwrite") + disp(">jpgwrite"); + jpgwrite('test.jpg',Rw,Gw,Bw); + stats=stat("test.jpg"); + assert(stats.size,6423); + disp(">jpgread"); + im = jpgread('test.jpg'); + Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3); + assert(all(Rw(:)-double(Rr(:))<35)); + assert(all(Gw(:)-double(Gr(:))<35)); + assert(all(Bw(:)-double(Br(:))<35)); + unlink('test.jpg'); +else + disp(">jpgread ... not available"); + disp(">jpgwrite ... not available"); +endif + +if exist("pngwrite") + disp(">pngwrite"); + pngwrite('test.png',Rw,Gw,Bw,Aw); + stats=stat("test.png"); + assert(stats.size,24738); + disp(">pngread"); + im = pngread('test.png'); + Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3); + assert(all(double(Rr(:))==Rw(:))); + assert(all(double(Gr(:))==Gw(:))); + assert(all(double(Br(:))==Bw(:))); + [im,Ar] = pngread('test.png'); + Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3); + assert(all(double(Rr(:))==Rw(:))); + assert(all(double(Gr(:))==Gw(:))); + assert(all(double(Br(:))==Bw(:))); + assert(all(double(Ar(:))==Aw(:))); + unlink('test.png'); +else + disp(">pngread ... not available"); + disp(">pngwrite ... not available"); +endif
new file mode 100644 --- /dev/null +++ b/inst/uintlut.m @@ -0,0 +1,60 @@ +## Copyright (C) 2004 Josep Mones i Teixidor +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{B} = } uintlut (@var{A},@var{LUT}) +## Computes matrix B by using A as an index to lookup table LUT. +## +## B = uintlut(A, LUT) calculates a matrix B by using @var{LUT} as a +## lookup table indexed by values in @var{A}. +## +## B class is the same as @var{LUT}. +## @end deftypefn + +## Author: Josep Mones i Teixidor <jmones@puntbarra.com> + +function B = uintlut(A, LUT) + if (nargin != 2) + usage("B = uintlut(A, LUT)"); + endif + + ## We convert indexing array A to double since even CVS version of + ## Octave is unable to use non-double arrays as indexing types. This + ## won't be needed in the future eventually. + B=LUT(double(A)); +endfunction + +%!demo +%! uintlut(uint8([1,2,3,4]),uint8([255:-1:0])); +%! % Returns a uint8 array [255,254,253,252] + +%!assert(uintlut(uint8([1,2,3,4]),uint8([255:-1:0])), uint8([255:-1:252])); +%!assert(uintlut(uint16([1,2,3,4]),uint16([255:-1:0])), uint16([255:-1:252])); +%!assert(uintlut(uint32([1,2,3,4]),uint32([255:-1:0])), uint32([255:-1:252])); +%!assert(uintlut(uint64([1,2,3,4]),uint64([255:-1:0])), uint64([255:-1:252])); + +% +% $Log$ +% Revision 1.1 2006/08/20 12:59:36 hauberg +% Changed the structure to match the package system +% +% Revision 1.2 2004/08/11 15:04:59 pkienzle +% Convert dos line endings to unix line endings +% +% Revision 1.1 2004/08/08 21:20:25 jmones +% uintlut and padarray functions added +% +%
new file mode 100644 --- /dev/null +++ b/inst/white.m @@ -0,0 +1,46 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} white (@var{n}) +## Create color colormap. +## (completly white) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = white (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("white: argument must be a scalar"); + endif + else + usage ("white (number)"); + endif + + if (number > 0) + map = ones (number, 3); + else + map = []; + endif + +endfunction
new file mode 100644 --- /dev/null +++ b/inst/winter.m @@ -0,0 +1,52 @@ +## Copyright (C) 1999,2000 Kai Habel +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +## -*- texinfo -*- +## @deftypefn {Function File} {} winter (@var{n}) +## Create color colormap. +## (blue to green) +## The argument @var{n} should be a scalar. If it +## is omitted, the length of the current colormap or 64 is assumed. +## @end deftypefn +## @seealso{colormap} + +## Author: Kai Habel <kai.habel@gmx.de> + +function map = winter (number) + + if (nargin == 0) + number = rows (colormap); + elseif (nargin == 1) + if (! is_scalar (number)) + error ("winter: argument must be a scalar"); + endif + else + usage ("winter (number)"); + endif + + if (number == 1) + map = [0, 0, 1]; + elseif (number > 1) + r = zeros (number, 1); + g = (0:number - 1)' ./ (number - 1); + b = 1 - g ./ 2; + + map = [r, g, b]; + else + map = []; + endif + +endfunction
deleted file mode 100644 --- a/isbw.m +++ /dev/null @@ -1,39 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{bool}= isbw (@var{BW}) -## returns true for a black-white (binary) image. -## All values must be either 0 or 1 -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 20/03/2000 - -function bool = isbw (BW) - - bool = 0; - if !(nargin == 1) - usage ("isbw(BW)"); - endif - - if !(is_matrix(BW)) - return; - endif - - bool = all (all ((BW == 1) + (BW == 0))); - -endfunction
deleted file mode 100644 --- a/isgray.m +++ /dev/null @@ -1,40 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{bool}= isgray (@var{I}) -## returns true for an intensity image. All intensity values must -## be in the range [0,1]. -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 20/03/2000 - -function bool = isgray (I) - - bool = 0; - - if !(nargin == 1) - usage ("isgray(I)"); - endif - - if (!is_matrix(I)) - return; - endif - - bool = all (all ((I >= 0) && (I <= 1))); - -endfunction
deleted file mode 100644 --- a/isind.m +++ /dev/null @@ -1,43 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WXTHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABXLXTY or FXTNESS FOR A PARTXCULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Xnc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{bool}= isind (@var{X}) -## returns true for an index image. All index values must -## be intergers and greater than or equal to 1. -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 20/03/2000 - -function ret = isind (X) - - if nargin != 1 - usage ("isind(X)"); - endif - - ret = isreal (X) && length (size (X)) == 2 ... - && all ( X(:) == floor (X(:)) ) && all ( X(:) >= 1 ); - -endfunction - -%!assert(isind([])) -%!assert(isind(1:10)) -%!assert(!isind(0:10)) -%!assert(isind(1)) -%!assert(!isind(0)) -%!assert(!isind([1.3,2.4])) -%!assert(isind([1,2;3,4]))
deleted file mode 100644 --- a/isrgb.m +++ /dev/null @@ -1,81 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{flag} = } isrgb (@var{A}) -## Returns true if parameter is a RGB image -## -## @code{flag=isrgb(A)} returns 1 if @var{A} is a RGB image and 0 if -## not. -## -## To the decide @code{isrgb} uses the follow algorithm: -## @itemize @bullet -## @item -## If @var{A} is of class double then it checks if all values are -## between 0 and 1, and if size is m-by-n-by-3. -## @item -## If @var{A} is of class uint16, uint8 or logical then it checks is m-by-n-by-3. -## @end itemize -## -## @strong{Compatibility notes:} -## -## Information needed on whether MATLAB accepts logical arrays as RGB -## images (now this functions accepts them if they are m-by-n-by-3 arrays. -## -## @end deftypefn - -## TODO: Check if logical arrays should be considered RGB - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function flag = isrgb(A) - if (nargin!=1) - usage("flag=isrgb(A)"); - endif - - if(ismatrix(A)) - flag=1; - s=size(A); - if(length(s)!=3 || s(3)!=3) - flag=0; ## false if not m-by-n-by-3 - elseif(strcmp(typeinfo(A),"matrix") && (any(A(:)<0) || any(A(:)>1))) - flag=0; ## false if class double but items are <0 or >1 - endif - else - flag=0; - endif -endfunction - - -%!demo -%! isrgb(rand(1,2,3)) -%! # A 1-by-2-by-3 double matrix with elements between 0 and 1 is a RGB image. - - -%!# Non-matrix -%!assert(isrgb("this is not a RGB image"),0); - -%!# Double matrix tests -%!assert(isrgb(rand(5,5)),0); -%!assert(isrgb(rand(5,5,1,5)),0); -%!assert(isrgb(rand(5,5,3,5)),0); -%!assert(isrgb(rand(5,5,3)),1); -%!assert(isrgb(ones(5,5,3)),1); -%!assert(isrgb(ones(5,5,3)+.0001),0); -%!assert(isrgb(zeros(5,5,3)-.0001),0); - -%!# Logical -%!assert(isrgb(logical(round(rand(5,5,3)))),1);
deleted file mode 100644 --- a/jet.m +++ /dev/null @@ -1,55 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} jet (@var{n}) -## Create color colormap. -## (dark blue through blue, cyan, green, yellow, red to dark red) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = jet (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("jet: argument must be a scalar"); - endif - else - usage ("jet (number)"); - endif - - if (number == 1) - map = [0, 0, 0.5]; - elseif (number > 1) - x = linspace(0, 1, number)'; - r = (x >= 3/8 & x < 5/8) .* (4 * x - 3/2)\ - + (x >= 5/8 & x < 7/8) + (x >= 7/8) .* (-4 * x + 9/2); - g = (x >= 1/8 & x < 3/8) .* (4 * x - 1/2)\ - + (x >= 3/8 & x < 5/8) + (x >= 5/8 & x < 7/8) .* (-4 * x + 7/2); - b = (x < 1/8) .* (4 * x + 1/2) + (x >= 1/8 & x < 3/8)\ - + (x >= 3/8 & x < 5/8) .* (-4 * x + 5/2); - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/jpgread.cc +++ /dev/null @@ -1,181 +0,0 @@ - // - // This is a hack into octave - // based on jpgread.c by jpgread by Drea Thomas, The Mathworks and the - // examples in the IJG distribution. - // - // (C) 1998 Andy Adler. This code is in the public domain - // USE THIS CODE AT YOUR OWN RISK - // - // $Id$ - // - -/* Modified: Stefan van der Walt <stefan@sun.ac.za> - * Date: 27 January 2004 - * - Manual error handler to prevent segfaults in Octave. - * - Use uint8NDArray for output. - */ - -/* - * Compilation: - * First, try - * mkoctfile jpgread.cc -ljpeg - * - * If this doesn't work, install the jpeg library which is part of - * "The Independent JPEG Group's JPEG software" collection. - * - * The jpeg library came from - * - * ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6.tar.gz - * - * Extract and build the library: - * tar xvfz jpegsrc.v6.tar.gz - * cd jpeg-6b - * ./configure - * make - * make test - * - * Compile this file using: - * mkoctfile jpgread.cc -I<jpeg-6b include dir> -L<jpeg-6b lib dir> -ljpeg - */ - -#include <octave/oct.h> -#include <iostream> -#include <csetjmp> - -#ifdef __cplusplus -extern "C" { -#endif - -#include "jpeglib.h" - -#ifdef __cplusplus -} //extern "C" -#endif - -struct oct_error_mgr { - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ -}; - -typedef struct oct_error_mgr * oct_error_ptr; - -METHODDEF(void) -oct_error_exit (j_common_ptr cinfo) -{ - /* cinfo->err really points to an oct_error_mgr struct, so coerce pointer */ - oct_error_ptr octerr = (oct_error_ptr) cinfo->err; - - /* Format error message and send to interpreter */ - char errmsg[JMSG_LENGTH_MAX]; - (octerr->pub.format_message)(cinfo, errmsg); - error("jpgread: %s", errmsg); - - /* Return control to the setjmp point */ - longjmp(octerr->setjmp_buffer, 1); -} - -DEFUN_DLD (jpgread, args, nargout , -"usage: I = jpgread('filename')\n\ -\n\ - Read a JPEG file from disk.\n\ -\n\ - For a grey-level image, the output is an MxN matrix. For a\n\ - colour image, three such matrices are returned (MxNx3),\n\ - representing the red, green and blue components. The output\n\ - is of class 'uint8'.\n\ -\n\ - See also: imread, im2double, im2gray, im2rgb.") -{ - octave_value_list retval; - int nargin = args.length(); - - FILE * infile; - - JSAMPARRAY buffer; - long row_stride; - struct jpeg_decompress_struct cinfo; - struct oct_error_mgr jerr; - - // - // We bail out if the input parameters are bad - // - if ((nargin != 1) || !args(0).is_string() || (nargout != 1)) { - print_usage (); - return retval; - } - - // - // Open jpg file - // - std::string filename = args(0).string_value(); - if ((infile = fopen(filename.c_str(), "rb")) == NULL) { - error("jpgread: couldn't open file %s", filename.c_str()); - return retval; - } - - // - // Initialize the jpeg library - // - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = oct_error_exit; - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - jpeg_destroy_decompress(&cinfo); - fclose(infile); - return retval; - } - - jpeg_create_decompress(&cinfo); - - // - // Read the jpg header to get info about size and color depth - // - jpeg_stdio_src(&cinfo, infile); - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - - // - // Allocate buffer for one scan line - // - row_stride = cinfo.output_width * cinfo.output_components; - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - - // - // Create an NDArray for the output. Loop through each of the - // scanlines and copy the image data from the buffer. - // - - dim_vector dim = dim_vector(); - dim.resize(3); - dim(0) = cinfo.output_height; - dim(1) = cinfo.output_width; - dim(2) = cinfo.output_components; - uint8NDArray out = uint8NDArray(dim, 0); - - Array<int> coord = Array<int> (3); - for (unsigned long j=0; cinfo.output_scanline < cinfo.output_height; j++) { - jpeg_read_scanlines(&cinfo, buffer, 1); - - coord(0) = j; - for (unsigned long i=0; i<cinfo.output_width; i++) { - coord(1) = i; - for (unsigned int c = 0; c < cinfo.output_components; c++) { - coord(2) = c; - out(coord) = buffer[0][i*cinfo.output_components+c]; - } - } - } - retval.append(out.squeeze()); - - // - // Clean up - // - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(infile); - - return retval; -}
deleted file mode 100644 --- a/jpgwrite.cc +++ /dev/null @@ -1,221 +0,0 @@ - // This is a hack into octave - // based on jpgwrite.c by jpgread by Drea Thomas, The Mathworks, and the - // examples in the IJG distribution. - // - // (C) 1998 Andy Adler. This code is in the public domain - // USE THIS CODE AT YOUR OWN RISK - // - // $Id$ - // - -#include <octave/oct.h> -#include <iostream> - -#ifdef __cplusplus -extern "C" { -#endif - -#include "jpeglib.h" - -#ifdef __cplusplus -} //extern "C" -#endif - -#define GRAYIMAGES - -/* - * Simple jpeg writing MEX-file. - * - * Synopsis: - * jpgwrite(filename,r,g,b,quality) - * - * Compilation: - * First, try - * mkoctfile jpgwrite.cc -ljpeg - * - * If this doesn't work, then do - * - * Calls the jpeg library which is part of - * "The Independent JPEG Group's JPEG software" collection. - * - * The jpeg library came from, - * - * ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6.tar.gz - */ - -DEFUN_DLD (jpgwrite, args, , -"JPGWRITE Write a JPEG file to disk.\n\ - jpgwrite('filename',R,G,B,quality) writes the specified file\n\ - using the Red, Green, and Blue intensity matrices, at the given quality.\n\ - \n\ - jpgwrite('filename',M,quality) writes a grey-scale image.\n\ - \n\ - Data must be [0 255] or the high bytes will be lost\n\ - \n\ - If specified, quality should be in the range 1-100 and will default to \n\ - 75 if not specified. 100 is best quality, 1 is best compression.\n\ - \n\ - See also JPGREAD") -{ - octave_value_list retval; - int nargin = args.length(); - - FILE * outfile; - - JSAMPARRAY buffer; - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - int quality=75; //default value - -// -// We bail out if the input parameters are bad -// - if (nargin < 2 || !args(0).is_string() ) { - print_usage (); - return retval; - } - - -// -// Open jpg file -// - std::string filename = args(0).string_value(); - if ((outfile = fopen(filename.c_str(), "wb")) == NULL) { - error("Couldn't open file"); - return retval; - } - -// -// Set Jpeg parameters -// - if (nargin == 3) { - quality= (int) args(2).double_value(); - } else if (nargin == 5) { - quality= (int) args(4).double_value(); - } - -// -// Initialize the jpeg library -// Read the jpg header to get info about size and color depth -// - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, outfile); - - -// -// set parameters for compression -// - - if ( nargin <= 3 ) { -// -// we're here because only one matrix of grey scale values was provided -// - Matrix avg= args(1).matrix_value(); - long image_width = args(1).columns(); - long image_height = args(1).rows(); - - - cinfo.image_width = image_width; /* image width and height, in pixels */ - cinfo.image_height = image_height; -#ifdef GRAYIMAGES - cinfo.input_components = 1; - cinfo.input_components = JCS_GRAYSCALE; -#else - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; -#endif - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); -// -// start compressor -// - jpeg_start_compress(&cinfo, TRUE); - -// -// Allocate buffer for one scan line -// - long row_stride = image_width * cinfo.input_components ; - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); -// -// Now, loop thru each of the scanlines. For each, copy the image -// data from the buffer, data must be [0 255] -// - for( long j=0; cinfo.next_scanline < cinfo.image_height; j++) { - for(unsigned long i=0; i<cinfo.image_width; i++) { -#ifdef GRAYIMAGES - buffer[0][i] = (unsigned char) avg(j,i); -#else - buffer[0][i*3+0] = (unsigned char) avg(j,i); - buffer[0][i*3+1] = (unsigned char) avg(j,i); - buffer[0][i*3+2] = (unsigned char) avg(j,i); -#endif - } - jpeg_write_scanlines(&cinfo, buffer,1); - } - - } // if nargin <= 3 - else { -// -// we're here because red green and blue matrices were provided -// we assume that they're the same size -// - Matrix red = args(1).matrix_value(); - Matrix green= args(2).matrix_value(); - Matrix blue = args(3).matrix_value(); - long image_width = args(1).columns(); - long image_height = args(1).rows(); - - if ( args(2).columns() != image_width || - args(3).columns() != image_width || - args(2).rows() != image_height || - args(3).rows() != image_height ) { - error("R,G,B matrix sizes aren't the same"); - return retval; - } - - cinfo.image_width = image_width; /* image width and height, in pixels */ - cinfo.image_height = image_height; - cinfo.input_components = 3; /* # of color components per pixel */ - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE ); -// -// start compressor -// - jpeg_start_compress(&cinfo, TRUE); - -// -// Allocate buffer for one scan line -// - long row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ - buffer = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); -// -// Now, loop thru each of the scanlines. For each, copy the image -// data from the buffer, data must be [0 255] -// - for( long j=0; cinfo.next_scanline < cinfo.image_height; j++) { - for(unsigned long i=0; i<cinfo.image_width; i++) { - buffer[0][i*3+0] = (unsigned char) red(j,i); - buffer[0][i*3+1] = (unsigned char) green(j,i); - buffer[0][i*3+2] = (unsigned char) blue(j,i); - } - jpeg_write_scanlines(&cinfo, buffer,1); - } - - } // else nargin > 3 - -// -// Clean up -// - - jpeg_finish_compress(&cinfo); - fclose(outfile); - jpeg_destroy_compress(&cinfo); - - - return retval; - -}
deleted file mode 100644 --- a/makelut.m +++ /dev/null @@ -1,73 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{lut} = } makelut (@var{fun},@var{n}) -## @deftypefnx {Function File} {@var{lut} = } makelut (@var{fun},@var{n},@var{P1},@var{P2},...) -## Create a lookup table which can be used by applylut. -## -## lut = makelut(fun,n) returns a vector which can be used by applylut -## as a lookup table. -## -## @var{fun} can be a function object as created by inline, or simply a -## string which contains the name of a function. @var{fun} should accept a -## @var{n}-by-@var{n} matrix whose elements are binary (0 or 1) and -## returns an scalar (actually anything suitable to be included in a -## vector). -## -## makelut calls @var{fun} with all possible matrices and builds a -## vector with its result, suitable to be used by applylut. The length -## of this vector is 2^(@var{n}^2), so 16 for 2-by-2 and 512 for 3-by-3. -## -## makelut also passes parameters @var{P1}, @var{P2}, .... to @var{fun}. -## -## @end deftypefn -## @seealso{applylut} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function lut = makelut(fun, n, varargin) - if (nargin < 2) - usage ("lut = makelut(fun, n [, ...])"); - endif - - if (n<2) - error ("makelut: n should be a natural number >= 2"); - endif - - nq=n^2; - c=2^nq; - lut=zeros(c,1); - w=reshape(2.^[nq-1:-1:0],n,n); - for i=0:c-1 - idx=bitand(w,i)>0; - lut(i+1)= feval(fun, idx, all_va_args); - endfor -endfunction - -%!demo -%! makelut(inline('sum(x(:))>=3','x'), 2) -%! % Returns '1' if one or more values -%! % in the input matrix are 1 - -%!assert(prod(makelut(inline('sum(x(:))==2','x'),2)==makelut(inline('sum(x(:))==a*b*c*d','x','a','b','c','d'),2,2/(3*4*5),3,4,5))); # test multiple params -%!assert(prod(makelut(inline('x(1,1)==1','x'),2)==[zeros(2^3,1);ones(2^3,1)])==1); # test 2-by-2 -%!assert(prod(makelut(inline('x(1,1)==1','x'),3)==[zeros(2^8,1);ones(2^8,1)])==1); # test 3-by-3 -%!assert(prod(makelut(inline('x(1,1)==1','x'),4)==[zeros(2^15,1);ones(2^15,1)])==1); # test 4-by-4 -%!assert(prod(makelut(inline('x(2,1)==1','x'),3)==[zeros(2^7,1);ones(2^7,1);zeros(2^7,1);ones(2^7,1)])==1); # another test for 3-by-3 - - -
deleted file mode 100644 --- a/mat2gray.m +++ /dev/null @@ -1,49 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{I}= mat2gray (@var{M},[min max]) -## converts a matrix to a intensity image -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 22/03/2000 - -function I = mat2gray (M, scale) - - if (nargin < 1|| nargin > 2) - usage ("mat2gray(...) number of arguments must be 1 or 2"); - endif - - if (!is_matrix (M)) - usage ("mat2gray(M,...) M must be a matrix"); - endif - - if (nargin == 1) - Mmin = min (min (M)); - Mmax = max (max (M)); - else - if (isvector (scale)) - Mmin = min (scale (1), scale (2)); - Mmax = max (scale (1), scale (2)); - endif - endif - - I = (M < Mmin) .* 0; - I = I + (M >= Mmin & M < Mmax) .* (1 / (Mmax - Mmin) * (M - Mmin)); - I = I + (M >= Mmax); - -endfunction
deleted file mode 100644 --- a/mean2.m +++ /dev/null @@ -1,39 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{m}= mean2 (@var{I}) -## returns the mean value for a 2d real type matrix. -## Uses @code{mean(I(:))} -## @end deftypefn -## @seealso{std2,mean} - - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 01/08/2000 - -function m = mean2 (I) - - if !(nargin == 1) - usage ("mean2(I)"); - endif - - if !(is_matrix(I) && isreal(I)) - error("argument must be a real type matrix"); - endif - - m = mean (I(:)); -endfunction
deleted file mode 100644 --- a/medfilt2.m +++ /dev/null @@ -1,68 +0,0 @@ -## Copyright (C) 2000 Teemu Ikonen -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} medfilt2(@var{A}, [@var{domain}, @var{padding}]) -## Two dimensional median filtering. -## -## Replaces elements of @var{A} with the median of their neighbours defined -## by true elements of logical matrix @var{domain}. The default @var{domain} -## is a 3 by 3 matrix with all elements equal to 1. If @var{domain} is 1 by 2 -## row vector, the domain matrix will be -## logical(ones(@var{domain}(2), @var{domain}(1))). -## -## Optional variable @var{padding} defines the padding used in augmenting -## the borders of @var{A}. See impad for details. -## -## @end deftypefn -## @seealso{ordfilt2} - -## Author: Teemu Ikonen <tpikonen@pcu.helsinki.fi> -## Created: 5.5.2000 -## Keywords: image processing median filtering - -%!test -%! b = [0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18]; -%! assert(medfilt2(b),[0,1,2,0;1,4,12,3;4,12,20,12;0,7,20,0]); - -function retval = medfilt2(A, varargin) - -padding = "zeros"; -domain = logical(ones(3,3)); - -for i=1:length(varargin) - a = varargin{i}; - if(ischar(a)) - padding = a; - elseif(isvector(a) && size(a) == [1, 2]) - domain = logical(ones(a(2), a(1))); - elseif(is_matrix(a)) - domain = logical(a); - endif -endfor - -n = sum(sum(domain)); -if((n - 2*floor(n/2)) == 0) % n even - more work - nth = floor(n/2); - a = ordfilt2(A, nth, domain, padding); - b = ordfilt2(A, nth + 1, domain, padding); - retval = (a + b)./2; -else - nth = floor(n/2) + 1; - retval = ordfilt2(A, nth, domain, padding); -endif - -endfunction
deleted file mode 100644 --- a/nlfilter.m +++ /dev/null @@ -1,167 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{B} = } nlfilter (@var{A}, [@var{m},@var{n}], @var{fun}) -## @deftypefnx {Function File} {@var{B} = } nlfilter (@var{A}, [@var{m},@var{n}], @var{fun}, ...) -## @deftypefnx {Function File} {@var{B} = } nlfilter (@var{A},'indexed', ...) -## Processes image in sliding blocks using user-supplied function -## -## @code{B=nlfilter(A,[m,n],fun)} passes sliding @var{m}-by-@var{n} -## blocks to user-supplied function @var{fun}. A block is build for -## every pixel in @var{A}, such as it is centered within the block. -## @var{fun} must return a scalar, and it is used to create matrix -## @var{B}. @var{nlfilter} pads the @var{m}-by-@var{n} block at the -## edges if necessary. -## -## Center of block is taken at ceil([@var{m},@var{n}]/2). -## -## @code{B=nlfilter(A,[m,n],fun,...)} behaves as described above but -## passes extra parameters to function @var{fun}. -## -## @code{B=nlfilter(A,'indexed',...)} assumes that @var{A} is an indexed -## image, so it pads the image using proper value: 0 for uint8 and -## uint16 images and 1 for double images. Keep in mind that if 'indexed' -## is not specified padding is always done using 0. -## -## @end deftypefn -## @seealso{colfilt,blkproc,inline} - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function B = nlfilter(A, varargin) - if(nargin<3) - error("nlfilter: invalid number of parameters."); - endif - - ## check 'indexed' presence - indexed=false; - p=1; - if(ischar(varargin{1}) && strcmp(varargin{1}, "indexed")) - indexed=true; - p+=1; - if(isa(A,"uint8") || isa(A,"uint16")) - padval=0; - else - padval=1; - endif - else - padval=0; - endif - - ## check [m,n] - if(!isvector(varargin{p})) - error("nlfilter: expected [m,n] but param is not a vector."); - endif - if(length(varargin{p})!=2) - error("nlfilter: expected [m,n] but param has wrong length."); - endif - sblk=varargin{p}(:); - p+=1; - - ## check fun - ## TODO: add proper checks for this one - if(nargin<p) - error("nlfilter: required parameters haven't been supplied."); - endif - fun=varargin{p}; - - ## remaining params are params to fun - ## extra params are p+1:nargin-1 - - ## We take an easy approach... feel free to optimize it (coding this - ## in C++ would be a great idea). - - ## Calculate center of block - c=ceil(sblk/2); - - ## Pre-padding - prepad=c-ones(2,1); - - ## Post-padding - postpad=sblk-c; - - ## Save A size - as=size(A); - - ## Pad data - if(all(prepad==postpad)) - if(any(prepad>0)) - A=padarray(A,prepad,padval,'both'); - endif - else - if(any(prepad>0)) - A=padarray(A,prepad,padval,'pre'); - endif - if(any(postpad>0)) - A=padarray(A,postpad,padval,'post'); - endif - endif - - ## calc end offsets - me=postpad(1)+prepad(1); - ne=postpad(2)+prepad(2); - - ## We concatenate everything to preserve fun return type - for i=1:as(1) - r=feval(fun,A(i:i+me,1:1+ne),varargin{p+1:nargin-1}); - for j=2:as(2) - r=horzcat(r,feval(fun,A(i:i+me,j:j+ne),varargin{p+1:nargin-1})); - endfor - if(i==1) - B=r; - else - B=vertcat(B,r); - endif - endfor - -endfunction - -%!demo -%! nlfilter(eye(10),[3,3],inline("any(x(:)>0)","x")) -%! # creates a "wide" diagonal - -%!assert(nlfilter(eye(4),[2,3],inline("sum(x(:))","x")),[2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1]); -%!assert(nlfilter(eye(4),'indexed',[2,3],inline("sum(x(:))","x")),[4,2,1,2;3,2,2,3;2,1,2,4;4,3,4,5]); -%!assert(nlfilter(eye(4),'indexed',[2,3],inline("sum(x(:))==y","x","y"),2),[0,1,0,1;0,1,1,0;1,0,1,0;0,0,0,0]!=0); - -% Check uint8 and uint16 padding -%!assert(nlfilter(uint8(eye(4)),'indexed',[2,3],inline("sum(x(:))","x")),[2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1]); -%!assert(nlfilter(uint16(eye(4)),'indexed',[2,3],inline("sum(x(:))","x")),[2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1]); - -% Check if function class is preserved -%!assert(nlfilter(uint8(eye(4)),'indexed',[2,3],inline("int8(sum(x(:)))","x")),int8([2,2,1,0;1,2,2,1;0,1,2,2;0,0,1,1])); - - - -% -% $Log$ -% Revision 1.5 2005/09/08 02:00:17 pkienzle -% [for Bill Denney] isstr -> ischar -% -% Revision 1.4 2004/11/15 16:04:20 pkienzle -% Fix tests for functions which return boolean matrices -% -% Revision 1.3 2004/09/03 13:28:32 jmones -% Corrected behaviour for int* and uint* types -% -% Revision 1.2 2004/08/15 19:43:11 jmones -% corrected a typo in doc -% -% Revision 1.1 2004/08/15 19:42:14 jmones -% nlfilter: Processes image in siliding blocks using user-supplied function -% -%
deleted file mode 100644 --- a/ordfilt2.m +++ /dev/null @@ -1,72 +0,0 @@ -## Copyright (C) 2000 Teemu Ikonen -## -## This program is free software; you can redistribute it and/or -## modify it under the terms of the GNU General Public License -## as published by the Free Software Foundation; either version 2 -## of the License, or (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -## -*- texinfo -*- -## @deftypefn {Function File} {} ordfilt2(@var{A}, @var{nth}, @var{domain}, [@var{S}, @var{padding}]) -## Two dimensional ordered filtering. -## -## Ordered filter replaces an element of @var{A} with the @var{nth} -## element of the sorted set of neighbours defined by the logical -## (boolean) matrix @var{domain}. -## Neighbour elements are selected to the sort if the corresponding -## element in the @var{domain} matrix is true. -## -## The optional variable @var{S} is a matrix of size(@var{domain}). -## Values of @var{S} corresponding to nonzero values of domain are -## added to values obtained from @var{A} when doing the sorting. -## -## Optional variable @var{padding} determines how the matrix @var{A} -## is padded from the edges. See impad for details. -## -## @end deftypefn -## @seealso{medfilt2} - - -## Author: Teemu Ikonen <tpikonen@pcu.helsinki.fi> -## Created: 5.5.2000 -## Keywords: image processing filtering - -function retval = ordfilt2(A, nth, domain, varargin) - -S = zeros(size(domain)); -padding = "zeros"; -for i=1:length(varargin) - a = varargin{:}; - if(ischar(a)) - padding = a; - elseif(is_matrix(a) && size(a) == size(domain)) - S = a; - endif -endfor - -if(!islogical(domain)) - % warning("domain should be a boolean matrix, converting"); - domain = logical(domain); -endif; - -xpad(1) = floor((size(domain, 2)+1)/2) - 1; -xpad(2) = size(domain,2) - xpad(1) - 1; -ypad(1) = floor((size(domain, 1)+1)/2) - 1; -ypad(2) = size(domain,1) - ypad(1) - 1; - -if(ypad(1) >= size(A,1) || xpad(1) >= size(A,2)) - error("domain matrix too large"); -endif; - -A = impad(A, xpad, ypad, padding); -retval = cordflt2(A, nth, domain, S); - -endfunction
deleted file mode 100644 --- a/padarray.m +++ /dev/null @@ -1,362 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{B} = } padarray (@var{A},@var{padsize}) -## @deftypefnx {Function File} {@var{B} = } padarray (@var{A},@var{padsize},@var{padval}) -## @deftypefnx {Function File} {@var{B} = } padarray (@var{A},@var{padsize},@var{padval},@var{direction}) -## Pads an array in a configurable way. -## -## B = padarray(A,padsize) pads an array @var{A} with zeros, where -## @var{padsize} defines the amount of padding to add in each dimension -## (it must be a vector of positive integers). -## -## Each component of @var{padsize} defines the number of elements of -## padding that will be added in the corresponding dimension. For -## instance, [4,5] adds 4 elements of padding in first dimension (vertical) -## and 5 in second dimension (horizontal). -## -## B = padarray(A,padsize,padval) pads @var{A} using the value specified -## by @var{padval}. @var{padval} can be a scalar or a string. Possible -## values are: -## @table @code -## @item 0 -## Pads with 0 as described above. This is the default behaviour. -## @item scalar -## Pads using @var{padval} as a padding value. -## @item 'circular' -## Pads with a circular repetition of elements in @var{A} (similar to -## tiling @var{A}). -## @item 'replicate' -## Pads 'replicating' values of @var{A} which are at the border of the -## array. -## @item 'symmetric' -## Pads with a mirror reflection of @var{A}. -## @end table -## -## B = padarray(A,padsize,padval,direction) pads @var{A} defining the -## direction of the pad. Possible values are: -## @table @code -## @item 'both' -## For each dimension it pads before the first element the number -## of elements defined by @var{padsize} and the same number again after -## the last element. This is the default value. -## @item 'pre' -## For each dimension it pads before the first element the number of -## elements defined by @var{padsize}. -## @item 'post' -## For each dimension it pads after the last element the number of -## elements defined by @var{padsize}. -## @end table -## @end deftypefn - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function B = padarray(A, padsize, padval, direction) - # Check parameters - if (nargin<2 || nargin>4) - usage ("B = padarray(A, padsize [, padval] [, direction])"); - endif - if (nargin<3) - padval=0; - endif - if (nargin<4) - direction='both'; - endif - - if (!isvector(padsize) || any(padsize<0)) - error("padarray: padsize must be a vector of positive integers."); - endif - - ## Assure padsize is a row vector - padsize=padsize(:).'; - - # Check direction - pre=false; - post=false; - switch(direction) - case('pre') - pre=true; - case('post') - post=true; - case('both') - post=true; - pre=true; - otherwise - error ("padarray: direction possible values are: 'pre', 'post' and 'both'"); - endswitch - - - B=A; - dim=1; - for s=padsize - if (s>0) - # padding in this dimension was requested - ds=size(B); - ds=[ds, ones(1,dim-length(ds))]; # data size - ps=ds; - ps(dim)=s; # padding size - - if (ischar(padval)) - # Init a "index all" cell array. All cases need it. - idx=cell(); - for i=1:length(ds) - idx{i}=1:ds(i); - endfor - - switch(padval) - case('circular') - complete=0; - D=B; - if (ps(dim)>ds(dim)) - complete=floor(ps(dim)/ds(dim)); - ps(dim)=rem(ps(dim),ds(dim)); - endif - if (pre) - for i=1:complete - B=cat(dim,D,B); - endfor - idxt=idx; - idxt{dim}=ds(dim)-ps(dim)+1:ds(dim); - B=cat(dim,D(idxt{:}),B); - endif - if (post) - for i=1:complete - B=cat(dim,B,D); - endfor - idxt=idx; - idxt{dim}=1:ps(dim); - B=cat(dim,B,D(idxt{:})); - endif - # end circular case - - case('replicate') - if (pre) - idxt=idx; - idxt{dim}=1; - pad=B(idxt{:}); - # can we do this without the loop? - for i=1:s - B=cat(dim,pad,B); - endfor - endif - if (post) - idxt=idx; - idxt{dim}=size(B,dim); - pad=B(idxt{:}); - for i=1:s - B=cat(dim,B,pad); - endfor - endif - # end replicate case - - case('symmetric') - if (ps(dim)>ds(dim)) - error("padarray: padding is longer than data using symmetric padding"); - endif - if (pre) - idxt=idx; - idxt{dim}=ps(dim):-1:1; - B=cat(dim,B(idxt{:}),B); - endif - if (post) - idxt=idx; - sbd=size(B,dim); - idxt{dim}=sbd:-1:sbd-ps(dim)+1; - B=cat(dim,B,B(idxt{:})); - endif - # end symmetric case - - otherwise - error("padarray: invalid string in padval parameter."); - - endswitch - # end cases where padval is a string - - elseif (isscalar(padval)) - # Handle fixed value padding - if (padval==0) - pad=zeros(ps,class(A)); ## class(pad) = class(A) - else - pad=padval*ones(ps,class(A)); ## class(pad) = class(A) - endif - if(pre&&post) - # check if this is not quicker than just 2 calls (one for each) - B=cat(dim,pad,B,pad); - elseif(pre) - B=cat(dim,pad,B); - elseif(post) - B=cat(dim,B,pad); - endif - else - error ("padarray: padval can only be a scalar or a string."); - endif - endif - dim+=1; - endfor -endfunction - -%!demo -%! padarray([1,2,3;4,5,6],[2,1]) -%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 0 - -%!demo -%! padarray([1,2,3;4,5,6],[2,1],5) -%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 5 - -%!demo -%! padarray([1,2,3;4,5,6],[2,1],0,'pre') -%! % pads [1,2,3;4,5,6] with a left and top border of 2 rows and 1 columns of 0 - -%!demo -%! padarray([1,2,3;4,5,6],[2,1],'circular') -%! % pads [1,2,3;4,5,6] with a whole 'circular' border of 2 rows and 1 columns -%! % border 'repeats' data as if we tiled blocks of data - -%!demo -%! padarray([1,2,3;4,5,6],[2,1],'replicate') -%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which -%! % 'replicates' edge data - -%!demo -%! padarray([1,2,3;4,5,6],[2,1],'symmetric') -%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which -%! % is symmetric to the data on the edge - -% Test default padval and direction -%!assert(padarray([1;2],[1]), [0;1;2;0]); -%!assert(padarray([3,4],[0,2]), [0,0,3,4,0,0]); -%!assert(padarray([1,2,3;4,5,6],[1,2]), \ -%! [zeros(1,7);0,0,1,2,3,0,0;0,0,4,5,6,0,0;zeros(1,7)]); - -% Test padding on 3D array -%!test -%! int8(0); % fail for octave <= 2.1.57 without crashing -%! assert(padarray([1,2,3;4,5,6],[3,2,1]), cat(3, \ -%! zeros(8,7), \ -%! [zeros(3,7); [zeros(2,2), [1,2,3;4,5,6], zeros(2,2)]; zeros(3,7)], \ -%! zeros(8,7))); - -% Test if default param are ok -%!assert(padarray([1,2],[4,5])==padarray([1,2],[4,5],0)); -%!assert(padarray([1,2],[4,5])==padarray([1,2],[4,5],0,'both')); - -% Test literal padval -%!assert(padarray([1;2],[1],i), [i;1;2;i]); - -% Test directions (horizontal) -%!assert(padarray([1;2],[1],i,'pre'), [i;1;2]); -%!assert(padarray([1;2],[1],i,'post'), [1;2;i]); -%!assert(padarray([1;2],[1],i,'both'), [i;1;2;i]); - -% Test directions (vertical) -%!assert(padarray([1,2],[0,1],i,'pre'), [i,1,2]); -%!assert(padarray([1,2],[0,1],i,'post'), [1,2,i]); -%!assert(padarray([1,2],[0,1],i,'both'), [i,1,2,i]); - -% Test vertical padsize -%!assert(padarray([1,2],[0;1],i,'both'), [i,1,2,i]); - -% Test circular padding -%!test -%! A=[1,2,3;4,5,6]; -%! B=repmat(A,7,9); -%! assert(padarray(A,[1,2],'circular','pre'), B(2:4,2:6)); -%! assert(padarray(A,[1,2],'circular','post'), B(3:5,4:8)); -%! assert(padarray(A,[1,2],'circular','both'), B(2:5,2:8)); -%! % This tests when padding is bigger than data -%! assert(padarray(A,[5,10],'circular','both'), B(2:13,3:25)); - -% Test replicate padding -%!test -%! A=[1,2;3,4]; -%! B=kron(A,ones(10,5)); -%! assert(padarray(A,[9,4],'replicate','pre'), B(1:11,1:6)); -%! assert(padarray(A,[9,4],'replicate','post'), B(10:20,5:10)); -%! assert(padarray(A,[9,4],'replicate','both'), B); - -% Test symmetric padding -%!test -%! A=[1:3;4:6]; -%! HA=[3:-1:1;6:-1:4]; -%! VA=[4:6;1:3]; -%! VHA=[6:-1:4;3:-1:1]; -%! B=[VHA,VA,VHA; HA,A,HA; VHA,VA,VHA]; -%! assert(padarray(A,[1,2],'symmetric','pre'), B(2:4,2:6)); -%! assert(padarray(A,[1,2],'symmetric','post'), B(3:5,4:8)); -%! assert(padarray(A,[1,2],'symmetric','both'), B(2:5,2:8)); - -% Repeat some tests with int* uint* class types -%!assert(padarray(int8([1;2]),[1]), int8([0;1;2;0])); -%!assert(padarray(uint8([3,4]),[0,2]), uint8([0,0,3,4,0,0])); -%!assert(padarray(int16([1;2]),[1],4), int16([4;1;2;4])); -%!assert(padarray(uint16([1;2]),[1],0), uint16([0;1;2;0])); -%!assert(padarray(int32([1;2]),[1],int32(4),'pre'), int32([4;1;2])); -%!assert(padarray(uint32([1;2]),[1],6,'post'), uint32([1;2;6])); - -% Test circular padding with int* uint* class types -%!test -%! A=int8([1,2,3;4,5,6]); -%! B=repmat(A,7,9); -%! assert(padarray(A,[1,2],'circular','pre'), B(2:4,2:6)); -%! assert(padarray(A,[1,2],'circular','post'), B(3:5,4:8)); -%! assert(padarray(A,[1,2],'circular','both'), B(2:5,2:8)); -%! % This tests when padding is bigger than data -%! assert(padarray(A,[5,10],'circular','both'), B(2:13,3:25)); - -% Test replicate padding with int* uint* class types -%!test -%! A=uint8([1,2;3,4]); -%! B=[ones(10,5,"uint8")*1,ones(10,5,"uint8")*2; \ -%! ones(10,5,"uint8")*3,ones(10,5,"uint8")*4]; -%! assert(padarray(A,[9,4],'replicate','pre'), B(1:11,1:6)); -%! assert(padarray(A,[9,4],'replicate','post'), B(10:20,5:10)); -%! assert(padarray(A,[9,4],'replicate','both'), B); - -% Test symmetric padding with int* uint* class types -%!test -%! A=int16([1:3;4:6]); -%! HA=int16([3:-1:1;6:-1:4]); -%! VA=int16([4:6;1:3]); -%! VHA=int16([6:-1:4;3:-1:1]); -%! B=[VHA,VA,VHA; HA,A,HA; VHA,VA,VHA]; -%! assert(padarray(A,[1,2],'symmetric','pre'), B(2:4,2:6)); -%! assert(padarray(A,[1,2],'symmetric','post'), B(3:5,4:8)); -%! assert(padarray(A,[1,2],'symmetric','both'), B(2:5,2:8)); - - - -% -% $Log$ -% Revision 1.6 2005/09/08 02:00:17 pkienzle -% [for Bill Denney] isstr -> ischar -% -% Revision 1.5 2004/09/03 18:33:11 pkienzle -% skip tests which use cat(3,X,Y) for octave <= 2.1.57 -% -% Revision 1.4 2004/09/03 13:37:10 jmones -% Corrected behaviour for int* and uint* types -% -% Revision 1.3 2004/08/15 19:21:50 jmones -% support column vector padsize -% -% Revision 1.2 2004/08/11 15:04:59 pkienzle -% Convert dos line endings to unix line endings -% -% Revision 1.1 2004/08/08 21:20:25 jmones -% uintlut and padarray functions added -% -%
deleted file mode 100644 --- a/pink.m +++ /dev/null @@ -1,55 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} pink (@var{n}) -## Create color colormap. -## (gives a sephia tone on b/w images) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = pink (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("pink: argument must be a scalar"); - endif - else - usage ("pink (number)"); - endif - - if (number == 1) - map = [0, 0, 0]; - elseif (number > 1) - x = linspace (0, 1, number)'; - r = (x < 3/8) .* (14/9 * x) + (x >= 3/8) .* (2/3 * x + 1/3); - g = (x < 3/8) .* (2/3 * x)\ - + (x >= 3/8 & x < 3/4) .* (14/9 * x - 1/3)\ - + (x >= 3/4) .* (2/3 * x + 1/3); - b = (x < 3/4) .* (2/3 * x) + (x >= 3/4) .* (2 * x - 1); - - map = sqrt ([r, g, b]); - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/pngcanvas.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * readpng.h - * - * Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - * Modified: Stefan van der Walt <stefan@sun.ac.za> - * Date: 28 January 2005 - * - Fix bugs, restructure - */ - -typedef struct -{ - int width; - int height; - int bit_depth; - int color_type; - unsigned char **row_pointers; -} canvas; - -//////////////Libcanvas/////////// -canvas *new_canvas(int width, int height, int stride) -{ - // Default stride if none given - if (stride==0) stride=width*4; - - // Clean allocation of canvas structure - canvas *can=new(canvas); - unsigned char *image_data = new unsigned char[stride*height]; - unsigned char **row_pointers = new unsigned char *[height]; - if (can == NULL || image_data == NULL || row_pointers == NULL) - { - if (can == NULL) delete can; - if (image_data == NULL) delete[] image_data; - if (row_pointers == NULL) delete[] row_pointers; - return NULL; - } - - // Fill in canvas structure - can->width=width; - can->height=height; - can->bit_depth=8; - can->color_type=PNG_COLOR_TYPE_RGB_ALPHA; - can->row_pointers = row_pointers; - for (int i=0; i < height; i++) row_pointers[i] = image_data + i*stride; - - return can; -} - -void delete_canvas(canvas *can) -{ - - if (can!=NULL) - { - delete[] can->row_pointers[0]; - delete[] can->row_pointers; - delete can; - } - return; -} -
deleted file mode 100644 --- a/pngread.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* - * pngread.cc - * - * Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - -Load PNG files to octave using libpng; - - PNG (Portable Network Graphics) is an extensible file format for the - lossless, portable, well-compressed storage of raster images. PNG pro- - vides a patent-free replacement for GIF and can also replace many com- - mon uses of TIFF. Indexed-color, grayscale, and truecolor images are - supported, plus an optional alpha channel. Sample depths range from 1 - to 16 bits. - -*/ - -/* - * Modified: Stefan van der Walt <stefan@sun.ac.za> - * Date: 28 January 2005 - * - Fix bugs, restructure - */ - -#include "png.h" -#include "pngcanvas.h" -#include <octave/oct.h> - -canvas *load_canvas(char *filename); - -DEFUN_DLD (pngread, args, nargout , -"-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{I}, @var{alpha}] =} pngread(@var{filename})\n\ -\n\ -Read a PNG file from disk.\n\ -\n\ -The image is returned as a matrix of dimension MxN (for grey-level images)\n\ -or MxNx3 (for colour images). The numeric type of @var{I} and @var{alpha}\n\ -is @code{uint8} for grey-level and RGB images, or @code{logical} for\n\ -black-and-white images.\n\ -\n\ -@end deftypefn\n\ -@seealso{imread}") -{ - octave_value_list retval; - int nargin = args.length(); - - // - // We bail out if the input parameters are bad - // - if (nargin != 1 || !args(0).is_string()) { - print_usage (); - return retval; - } - - // - // Load png file - // - canvas *pic=load_canvas((char *)args(0).string_value().c_str()); - if (!pic) return retval; - - dim_vector dim = dim_vector(); - dim.resize(3); - dim(0) = pic->height; - dim(1) = pic->width; - dim(2) = 3; - - if ( (pic->color_type == PNG_COLOR_TYPE_GRAY) || - (pic->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || - ((pic->color_type == PNG_COLOR_TYPE_PALETTE) && (pic->bit_depth == 1)) ) - dim(2) = 1; - - if (pic->bit_depth > 1 && pic->bit_depth < 8) - pic->bit_depth = 8; - - NDArray out(dim); - - dim.resize(2); - NDArray alpha(dim); - - Array<int> coord = Array<int> (3); - - for (unsigned long j=0; j < pic->height; j++) { - coord(0) = j; - for (unsigned long i=0; i < pic->width; i++) { - coord(1) = i; - - for (int c = 0; c < out.dims()(2); c++) { - coord(2) = c; - out(coord) = pic->row_pointers[j][i*4+c]; - } - alpha(j,i) = pic->row_pointers[j][i*4+3]; - } - } - out = out.squeeze(); - - switch (pic->bit_depth) { - case 1: - retval.append((boolNDArray)out); - retval.append((boolNDArray)alpha); - break; - case 8: - retval.append((uint8NDArray)out); - retval.append((uint8NDArray)alpha); - break; - case 16: - retval.append((uint16NDArray)out); - retval.append((uint16NDArray)alpha); - break; - default: - retval.append(out); - retval.append(alpha); - } - - delete_canvas(pic); - return retval; -} - -canvas *load_canvas(char *filename) -{ - png_structp png_ptr; - png_infop info_ptr; - - FILE *infile = fopen(filename,"r"); - if (!infile) { - error("pngread could not open file %s", filename); - return NULL; - } - - unsigned char sig[8]; - fread(sig,1,8,infile); - if (!png_check_sig(sig,8)) { - error("pngread invalid signature in %s", filename); - fclose(infile); - return NULL; - } - - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); - if (!png_ptr) { - error("pngread out of memory"); - fclose(infile); - return NULL; - } - - info_ptr = png_create_info_struct(png_ptr); - if(!info_ptr) { - error("pngread can't generate info"); - png_destroy_read_struct(&png_ptr,NULL,NULL); - fclose(infile); - return NULL; - } - - /* Set error handling */ - if (setjmp(png_jmpbuf(png_ptr))) { - error("pngread: libpng exited abnormally"); - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - fclose(infile); - return NULL; - } - - png_init_io(png_ptr, infile); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); - - png_uint_32 width,height; - int color_type, bit_depth; - png_get_IHDR(png_ptr,info_ptr,&width,&height, - &bit_depth,&color_type,NULL,NULL,NULL); - - /* Transform grayscale images with depths < 8-bit to 8-bit, change - * paletted images to RGB, and add a full alpha channel if there is - * transparency information in a tRNS chunk. - */ - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - } - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - png_set_gray_1_2_4_to_8(png_ptr); - } - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { //add alpha - png_set_tRNS_to_alpha(png_ptr); - } - - // Always transform image to RGB - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - png_set_gray_to_rgb(png_ptr); - - // If no alpha layer is present, create one - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_RGB) - png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); - - if (bit_depth < 8) { - png_set_packing(png_ptr); - } - - // For now, use 8-bit only - if (bit_depth == 16) { - png_set_strip_16(png_ptr); - } - - png_read_update_info(png_ptr,info_ptr); - - // Read the data from the file - int stride = png_get_rowbytes(png_ptr, info_ptr); - canvas *can = new_canvas(width, height, stride); - - if (can) { - png_read_image(png_ptr, can->row_pointers); - } else { - error("pngread out of memory"); - } - - png_read_end(png_ptr,NULL); - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); - - fclose(infile); - - // Set color type and depth. Used to determine octave output arguments. - can->color_type = color_type; - can->bit_depth = bit_depth; - return can; -}
deleted file mode 100644 --- a/pngwrite.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* - * pngwrite.cc - * - * Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* - -Write PNG files to disk from octave - - PNG (Portable Network Graphics) is an extensible file format for the - lossless, portable, well-compressed storage of raster images. PNG pro- - vides a patent-free replacement for GIF and can also replace many com- - mon uses of TIFF. Indexed-color, grayscale, and truecolor images are - supported, plus an optional alpha channel. Sample depths range from 1 - to 16 bits. - -*/ - -/* - * Modified: Stefan van der Walt <stefan@sun.ac.za> - * Date: 28 January 2005 - * - Fix bugs, restructure - */ - -#include "png.h" -#include "pngcanvas.h" -#include <octave/oct.h> - -void save_canvas(canvas *can, char *filename); - -DEFUN_DLD (pngwrite, args, ,"\ -pngwrite writes a png file to the disk.\n\ - pngwrite('filename',R,G,B,A) writes the specified file\n\ - using the Red, Green, Blue and Alpha matrices.\n\ - \n\ - Data must be [0 255] or the high bytes will be lost.") -{ - octave_value_list retval; - int nargin = args.length(); - - // - // We bail out if the input parameters are bad - // - if (nargin < 5 || !args(0).is_string() ) { - print_usage (); - return retval; - } - - Matrix red = args(1).matrix_value(); - Matrix green= args(2).matrix_value(); - Matrix blue = args(3).matrix_value(); - Matrix alpha= args(4).matrix_value(); - - long image_width = args(1).columns(); - long image_height = args(1).rows(); - - if ( args(2).columns() != image_width || - args(3).columns() != image_width || - args(4).columns() != image_width || - args(2).rows() != image_height || - args(3).rows() != image_height || - args(4).rows() != image_height ) - { - error("pngwrite R,G,B,A matrix sizes aren't the same"); - return retval; - } - - canvas *pic=new_canvas(image_width, image_height, image_width*4); - if (!pic) { - error("pngwrite out of memory"); - return retval; - } - - for(int i=0; i < pic->width; i++) { - for(int j=0; j < pic->height; j++) { - pic->row_pointers[j][i*4+0]=(unsigned char)(red(j,i)); - pic->row_pointers[j][i*4+1]=(unsigned char)(green(j,i)); - pic->row_pointers[j][i*4+2]=(unsigned char)(blue(j,i)); - pic->row_pointers[j][i*4+3]=(unsigned char)(alpha(j,i)); - } - } - - - save_canvas(pic,(char *)args(0).string_value().c_str()); - delete_canvas(pic); - - return retval; -} - -void save_canvas(canvas *can,char *filename) -{ - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - - fp = fopen(filename, "wb"); - if (fp == NULL) { - error("pngwrite could not open %s", filename); - return; - } - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { - fclose(fp); - error("pngwrite: cannot create write structure"); - return; - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - fclose(fp); - error("pngwrite: cannot not create image structure"); - png_destroy_write_struct(&png_ptr, png_infopp_NULL); - return; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - error("pngread: libpng exited abnormally"); - return; - } - - png_init_io(png_ptr, fp); - png_set_compression_level(png_ptr, 3); - - png_set_IHDR(png_ptr, info_ptr, can->width, can->height, - can->bit_depth, can->color_type, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - - png_set_gAMA(png_ptr, info_ptr, 0.7); - - time_t gmt; - png_time mod_time; - png_text text_ptr[2]; - time(&gmt); - png_convert_from_time_t(&mod_time, gmt); - png_set_tIME(png_ptr, info_ptr, &mod_time); - text_ptr[0].key = "Created by"; - text_ptr[0].text = "Octave"; - text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; - - png_set_text(png_ptr, info_ptr, text_ptr, 1); - - png_write_info(png_ptr, info_ptr); - png_write_image(png_ptr, can->row_pointers); - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); -}
deleted file mode 100644 --- a/poly2mask.m +++ /dev/null @@ -1,253 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{BW} = } poly2mask (@var{x},@var{y},@var{m},@var{n}) -## Convert a polygon to a region mask -## -## BW=poly2mask(x,y,m,n) converts a polygon, specified by a list of -## vertices in @var{x} and @var{y} and returns in a @var{m}-by-@var{n} -## logical mask @var{BW} the filled polygon. Region inside the polygon -## is set to 1, values outside the shape are set to 0. -## -## @var{x} and @var{y} should always represent a closed polygon, first -## and last points should be coincident. If they are not poly2mask will -## close it for you. If @var{x} or @var{y} are fractional they are -## nearest integer. -## -## If all the polygon or part of it falls outside the masking area -## (1:m,1:n), it is discarded or clipped. -## -## This function uses scan-line polygon filling algorithm as described -## in http://www.cs.rit.edu/~icss571/filling/ with some minor -## modifications: capability of clipping and scan order, which can -## affect the results of the algorithm (algorithm is described not to -## reach ymax, xmax border when filling to avoid enlarging shapes). In -## this function we scan the image backwards (we begin at ymax and end -## at ymin), and we don't reach ymin, xmin, which we believe should be -## compatible with MATLAB. -## @end deftypefn - - -## TODO: check how to create a logical BW without any conversion - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function BW = poly2mask(x, y, m, n) - if (nargin!=4) - usage("BW = poly2mask(x, y, m, n)"); - endif - - ## check x and y - x=round(x(:)'); - y=round(y(:)'); - if(length(x)<3) - error("poly2mask: polygon must have at least 3 vertices."); - endif - if(length(x)!=length(y)) - error("poly2mask: length of x doesn't match length of y."); - endif - - ## create output matrix - uint8(0); ## This fails for octave < 2.1.58 - BW=logical(zeros(m,n,"uint8")); - - ## close polygon if needed - if((x(1)!=x(length(x)))||(y(1)!=y(length(y)))) - x=horzcat(x,x(1)); - y=horzcat(y,y(1)); - endif - - ## build global edge table - ex=[x(1:length(x)-1);x(1,2:length(x))]; ## x values for each edge - ey=[y(1:length(y)-1);y(1,2:length(y))]; ## y values for each edge - idx=find(ey(1,:)!=ey(2,:)); ## eliminate horizontal edges - ex=ex(:,idx); - ey=ey(:,idx); - eminy=min(ey); ## minimum y for each edge - emaxy=max(ey); ## maximum y for each edge - t=ey==[eminy;eminy]; ## values associated to miny - exminy=ex(:)(find(t)); ## x values associated to min y - exmaxy=ex(:)(find(!t)); ## x values associated to max y - emaxy=emaxy'; ## we want them vertical now... - eminy=eminy'; - m_inv=(exmaxy-exminy)./(emaxy-eminy); ## calculate inverse slope - ge=[emaxy, eminy, exmaxy, m_inv]; ## build global edge table - ge=sortrows(ge,[1,3]); ## sort on eminy and exminy - - ## we add an extra dummy edge at the end just to avoid checking - ## while indexing it - ge=[-Inf,-Inf,-Inf,-Inf;ge]; - - ## initial parity is even (0) - parity=0; - - ## init scan line set to bottom line - sl=ge(size(ge,1),1); - - ## init active edge table - ## we use a loop because the table is sorted and edge list could be - ## huge - ae=[]; - gei=size(ge,1); - while sl==ge(gei,1) - ae=[ge(gei,2:4);ae]; - gei-=1; - endwhile - - ## calc minimum y to draw - miny=min(y); - if (miny<1) - miny=1; - endif - - while sl>=miny - ## check vert clipping - if(sl<=m) - ## draw current scan line - ## we have to round because 1/m is fractional - ie=round(reshape(ae(:,2),2,size(ae)/2)); - - ## this discards left border of image (this differs from version at - ## http://www.cs.rit.edu/~icss571/filling/ which discards right - ## border) but keeps an exception when the point is a vertex. - ie(1,:)+=ie(1,:)!=ie(2,:); - - ## we'll clip too, just in case m,n is not big enough - ie(1,find(ie(1,:)<1))=1; - ie(2,find(ie(2,:)>n))=n; - - ## we eliminate segments outside window - ie=ie(:,find(ie(1,:)<=n)); - ie=ie(:,find(ie(2,:)>=1)); - for i=1:columns(ie) - BW(sl,ie(1,i):ie(2,i))=true; - endfor - endif - - ## decrement scan line - sl-=1; - - ## eliminate edges that eymax==sl - ## this discards ymin border of image (this differs from version at - ## http://www.cs.rit.edu/~icss571/filling/ which discards ymax). - ae=ae(find(ae(:,1)!=sl),:); - - ## update x (x1=x0-1/m) - ae(:,2)-=ae(:,3); - - ## update ae with new values - while sl==ge(gei,1) - ae=vertcat(ae,ge(gei,2:4)); - gei-=1; - endwhile - - ## order the edges in ae by x value - if(rows(ae)>0) - ae=sortrows(ae,2); - endif - endwhile -endfunction - - -%!demo -%! s=[0:pi/4:2*pi]; -%! x=cos(s)*90+101; -%! y=sin(s)*90+101; -%! bw=poly2mask(x,y,200,200); -%! imshow(bw); -%! %Creates a filled octagon - -%!demo -%! s=[0:2*pi/5:pi*4]; -%! s=s([1,3,5,2,4,6]); -%! x=cos(s)*90+101; -%! y=sin(s)*90+101; -%! bw=poly2mask(x,y,200,200); -%! imshow(bw); -%! %Creates a 5-vertex star - -%!# Convex polygons - -%!shared xs, ys, Rs, xt, yt, Rt -%! xs=[3,3,10,10]; -%! ys=[4,12,12,4]; -%! Rs=zeros(16,14); -%! Rs(5:12,4:10)=1; -%! Rs=logical(Rs); -%! xt=[1,4,7]; -%! yt=[1,4,1]; -%! Rt=[0,0,0,0,0,0,0; -%! 0,0,1,1,1,1,0; -%! 0,0,0,1,1,0,0; -%! 0,0,0,1,0,0,0; -%! 0,0,0,0,0,0,0]; -%! Rt=logical(Rt); - -%!assert(poly2mask(xs,ys,16,14),Rs); # rectangle -%!assert(poly2mask(xs,ys,8,7),Rs(1:8,1:7)); # clipped -%!assert(poly2mask(xs-7,ys-8,8,7),Rs(9:16,8:14)); # more clipping - -%!assert(poly2mask(xt,yt,5,7),Rt); # triangle -%!assert(poly2mask(xt,yt,3,3),Rt(1:3,1:3)); # clipped - - -%!# Concave polygons - -%!test -%! x=[3,3,5,5,8,8,10,10]; -%! y=[4,12,12,8,8,11,11,4]; -%! R=zeros(16,14); -%! R(5:12,4:5)=1; -%! R(5:8,6:8)=1; -%! R(5:11,9:10)=1; -%! R=logical(R); -%! assert(poly2mask(x,y,16,14), R); - -%!# Complex polygons -%!test -%! x=[1,5,1,5]; -%! y=[1,1,4,4]; -%! R=[0,0,0,0,0,0; -%! 0,0,1,1,0,0; -%! 0,0,1,1,0,0; -%! 0,1,1,1,1,0; -%! 0,0,0,0,0,0]; -%! R=logical(R); -%! assert(poly2mask(x,y,5,6), R); - - - - - -% -% $Log$ -% Revision 1.5 2004/09/07 14:47:50 pkienzle -% Avoid segfaults on pre-2.1.58 octave. Invisible whitespace changes. -% -% Revision 1.4 2004/09/03 17:12:36 jmones -% Uses uint8 to save some temporal memory (suggested by David Bateman) -% -% Revision 1.3 2004/09/03 13:32:07 jmones -% Work with logical arrays from BW creation -% -% Revision 1.2 2004/08/11 17:39:51 jmones -% Algorithm url in docs corrected. -% -% Revision 1.1 2004/08/11 17:34:11 jmones -% poly2mask added: creates filled polygon bw mask -% -%
deleted file mode 100644 --- a/prism.m +++ /dev/null @@ -1,48 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} prism (@var{n}) -## Create color colormap. -## (cycling trough red, orange, yellow, green, blue and violet) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = prism (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("prism: argument must be a scalar"); - endif - else - usage ("prism (number)"); - endif - - p = [1, 0, 0; 1, 1/2, 0; 1, 1, 0; 0, 1, 0; 0, 0, 1; 2/3, 0, 1]; - - if (rem (number, 6) == 0) - map = kron(ones (fix (number / 6), 1), p); - else - map = [kron(ones (fix (number / 6), 1), p); p(1:rem (number, 6), :)]; - endif - -endfunction
deleted file mode 100644 --- a/qtdecomp.m +++ /dev/null @@ -1,328 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{S} = } qtdecomp (@var{I}) -## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{threshold}) -## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{threshold},@var{mindim}) -## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{threshold},@var{[mindim maxdim]}) -## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{fun}) -## @deftypefnx {Function File} {@var{S} = } qtdecomp (@var{I},@var{fun},@var{P1},@var{P2},...) -## Performs quadtree decomposition -## -## qtdecomp decomposes a square image @var{I} into four equal-sized -## blocks. Then it performs some kind of test on each block to decide if -## it should decompose them further. This process is repeated -## iteratively until there's no block left to be decomposed. -## -## Note that blocks are not decomposed if their dimensions are not even. -## -## The output is a sparse matrix whose non-zero elements determine the -## position of the block (the element is at top-left position in the -## block) and size of each block (the value of the element determines -## length of a side of the square-shaped block). -## -## S = qtdecomp(I) decomposes an intensity image @var{I} as described -## above. By default it doesn't split a block if all elements are equal. -## -## S = qtdecomp(I, threshold) decomposes an image as decribed, but only -## splits a block if the maximum value in the block minus the minimum -## value is greater than @var{threshold}, which is a value between 0 and -## 1. If @var{I} is of class uint8, @var{threshold} is multiplied by 255 -## before use. Also, if@var{I} is of class uint16, @var{threshold} is -## multiplied by 65535. -## -## S = qtdecomp(I, threshold, mindim) decomposes an image using the -## @var{threshold} as just described, but doesn't produce blocks smaller -## than mindim. -## -## S = qtdecomp(I, threshold, [mindim maxdim]) decomposes an image as -## described, but produces blocks that can't be bigger than maxdim. It -## decomposes to maxdim even if it isn't needed if only @var{threshold} -## was considered. -## -## S = qtdecomp(I, fun) decomposes an image @var{I} and uses function -## @var{fun} to decide if a block should be splitted or not. @var{fun} -## is called with a m-by-m-by-k array of m-by-m blocks to be -## considered, and should return a vector of size k, whose elements -## represent each block in the stacked array. @var{fun} sets the -## corresponding value to 1 if the block should be split, and 0 -## otherwise. -## -## S = qtdecomp(I, fun, ...) behaves as qtdecomp(I, fun) but passes -## extra parameters to @var{fun}. -## -## @end deftypefn -## @seealso qtgetblk, qtsetblk - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function S = qtdecomp(I, p1, varargin) - if (nargin<1) - usage("S=qtdecomp(I)"); - endif - - if (!ismatrix(I) || size(I,1)!=size(I,2)) - error("qtdecomp: I should be a square matrix."); - endif - - ## current size (assumed to be square) - curr_size=size(I,1); - - ## initial mindim to a sensible value - mindim=1; - - ## sensible default maxdim value - maxdim=curr_size; - - if (nargin<2) - ## Initialize decision method variable - ## We could have implemented threshold as a function and use an - ## uniform interface (function handle) to decide whether to split or - ## not blocks. We have decided not to do so because block - ## rearrangement that is needed as a parameter to functions is - ## expensive. - decision_method=0; - elseif (isreal(p1)) - ## p1 is threshold - threshold=p1; - decision_method=1; - - if(strcmp(typeinfo(I), 'uint8 matrix')) - threshold*=255; - elseif(strcmp(typeinfo(I), 'uint16 matrix')) - threshold*=65535; - endif - - if (nargin>3) - usage("S=qtdecomp(I,threshold,mindim), \ - S=qtdecomp(I,threshold,[mindim maxdim])"); - elseif (nargin==3) - dims=varargin{1}; - if (isvector(dims)&&length(dims)==2) - mindim=dims(1); - maxdim=dims(2); - elseif (isreal(dims)) - mindim=dims; - else - error("qtdecomp: third parameter must be 'mindim' or '[mindim maxdim]'"); - endif - ## we won't check if mindim or maxdim are powers of 2. It's too - ## restrictive and don't need it at all. - endif - - elseif strcmp(typeinfo(p1),"function handle") ... - || strcmp(typeinfo(p1),"inline function") - ## function handles seem to return true to isscalar - fun=p1; - decision_method=2; - else - error("qtdecomp: second parameter must be a integer (threshold) or a function handle (fun)."); - endif - - ## initialize results matrices - res=[]; - - ## bool to flag end - finished=false; - - ## array of offsets to blocks to evaluate - offsets=[1,1]; - - if (maxdim<mindim) - error("qtdecomp: mindim must be smaller than maxdim."); - endif - - ## See if we have to split a minimum regarless other considerations. - if (maxdim<curr_size) - initial_splits=ceil(log2(curr_size/maxdim)); - if(initial_splits>0) - divs=2^initial_splits; - if (rem(curr_size,divs)!=0) - error("qtdecomp: Can't decompose I enough times to fulfill maxdim requirement."); - endif - ## update curr_size - curr_size/=divs; - if(curr_size<mindim) - error("qtdecomp: maxdim restriction collides with mindim restriction."); - endif - els=transpose([0:divs-1]*curr_size+1); - offsets=[kron(els,ones(divs,1)), kron(ones(divs,1),els)]; - endif - endif - - while(!finished && rows(offsets)>0) - ## check other ending conditions: - ## is size is odd? - ## is splitted size < than mindim? - if ((rem(curr_size,2)!=0)||((curr_size/2)<mindim)) - ## can't continue, lets add current evaluation blocks to results - res=[res; offsets, ones(size(offsets,1),1)*curr_size]; - finished = true; - else - if (decision_method<2) - db=logical(ones(rows(offsets),1)); - for r=1:rows(offsets) - o=offsets(r,:); - fo=offsets(r,:)+curr_size-1; - - if(decision_method==0) - ## is everything equal? - if (all(I(o(1),o(2))==I(o(1):fo(1),o(2):fo(2)))) - db(r)=0; - endif - else - ## check threshold - t=I(o(1):fo(1),o(2):fo(2)); - t=t(:); - if ((max(t)-min(t))<=threshold) - db(r)=0; - endif - endif - endfor - elseif(decision_method==2) - ## function handle decision method - ## build blocks - b=zeros(curr_size,curr_size,rows(offsets)); - rbc=offsets(:,1:2)+curr_size-1; - for r=1:rows(offsets) - b(:,:,r)=I(offsets(r,1):rbc(r,1),offsets(r,2):rbc(r,2)); - endfor - - db=feval(fun, b, varargin{:}); - else - error("qtdecomp: execution shouldn't reach here. Please report this as a bug."); - endif - - ## Add blocks that won't divide to results - nd=offsets(find(!db),:); - res=[res; nd, ones(size(nd,1),1)*curr_size]; - - ## Update curr_size for next iteration - curr_size/=2; - - ## Prepare offsets for next iteration - otemp=offsets(find(db),:); - hs=ones(rows(otemp),1)*curr_size; - zs=zeros(size(hs)); - offsets=[otemp;otemp+[hs,zs];otemp+[zs,hs];otemp+[hs,hs]]; - endif - endwhile - - S=sparse(res(:,1),res(:,2),res(:,3),size(I,1),size(I,2)); -endfunction - - -%!demo -%! full(qtdecomp(eye(8))) -%! %It finds 2 big blocks of 0 and it decomposes further where 0 and 1 are mixed. - - -%!# Test if odd-sized limits split -%!assert(full(qtdecomp(eye(5))), reshape([5,zeros(1,24)],5,5)); -%!assert(full(qtdecomp(eye(6))), repmat(reshape([3,zeros(1,8)],3,3),2,2)); - -%!# Test 'equal' method -%!test -%! a=ones(2,2); -%! b=[2,0;0,0]; -%! assert(full(qtdecomp(eye(4))), [a,b;b,a]); - -%!shared A, B2, B4 -%! A=[ 1, 4, 2, 5,54,55,61,62; -%! 3, 6, 3, 1,58,53,67,65; -%! 3, 6, 3, 1,58,53,67,65; -%! 3, 6, 3, 1,58,53,67,65; -%! 23,42,42,42,99,99,99,99; -%! 27,42,42,42,99,99,99,99; -%! 23,22,26,25,99,99,99,99; -%! 22,22,24,22,99,99,99,99]; -%! B2=[2,0;0,0]; -%! B4=zeros(4); B4(1,1)=4; - -%!test -%! R=[ones(4,8); [ones(2),B2;ones(2,4)], B4]; -%! assert(full(qtdecomp(A)), R); -%! assert(full(qtdecomp(A,0)), R); - -%!# Test 'threshold' method -%!test -%! R=[ones(4,8); [ones(2),B2;B2,ones(2)],B4]; -%! assert(full(qtdecomp(A,1)), R); - -%!test -%! R=[[B4,[B2,B2;B2,B2]]; [[ones(2),B2;B2,B2],B4]]; -%! assert(full(qtdecomp(A,10)), R); - -%!test -%! R=[[B4,[B2,B2;B2,B2]]; [[B2,B2;B2,B2],B4]]; -%! assert(full(qtdecomp(A,10,2)), R); - -%!assert(full(qtdecomp(A,100,[2, 4])), [B4,B4;B4,B4]); - -%!# Test 'fun' method -%!# Can't define a function inside tests because Octave -%!# complains about nested functions. If you know how to -%!# do it please add function handle tests. - -%!# inline version -%!# We use [size(A),1](3) as a trick since size(A,3) fails if A is 2D. - -%!# no params -%!test -%! first_eq=inline("(A(1,1,:)!=(54*ones(1,1,[size(A),1](3))))(:)","A"); -%! assert(full(qtdecomp(A,first_eq)),[ones(4),B4;ones(4,8)]); - -%!# 1 param -%!test -%! first_eq=inline("(A(1,1,:)!=(c*ones(1,1,[size(A),1](3))))(:)","A","c"); -%! assert(full(qtdecomp(A,first_eq,54)),[ones(4),B4;ones(4,8)]); - -%!# 3 params -%!test -%! first_eq=inline("(A(1,1,:)!=((c1+c2+c3)*ones(1,1,[size(A),1](3))))(:)","A","c1","c2","c3"); -%! assert(full(qtdecomp(A,first_eq,4,40,10)),[ones(4),B4;ones(4,8)]); - - - -% -% $Log$ -% Revision 1.8 2006/01/03 02:09:15 pkienzle -% Reorder tests so that shared variables are displayed unless relevant. -% -% Revision 1.7 2006/01/02 22:05:06 pkienzle -% Reduce number of shared variables in tests -% -% Revision 1.6 2004/09/09 19:36:35 jmones -% all_va_args -> varargin{:}. Now works on 2.1.58 -% -% Revision 1.5 2004/09/08 14:07:22 pkienzle -% Fix test for 'inline function' -% -% Revision 1.4 2004/08/11 19:52:41 jmones -% qtsetblk added -% -% Revision 1.3 2004/08/11 00:05:21 jmones -% seealso qtgetblk added to doc -% -% Revision 1.2 2004/08/10 00:19:42 jmones -% Corrected misleading comment. -% -% Revision 1.1 2004/08/09 01:48:54 jmones -% Added qtdecomp: quadtree decomposition -% -% -
deleted file mode 100644 --- a/qtgetblk.m +++ /dev/null @@ -1,151 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {[@var{vals}] = } qtgetblk (@var{I},@var{S},@var{dim}) -## @deftypefnx {Function File} {[@var{vals},@var{idx}] = } qtgetblk (@var{I},@var{S},@var{dim}) -## @deftypefnx {Function File} {[@var{vals},@var{r},@var{c}] = } qtgetblk (@var{I},@var{S},@var{dim}) -## Obtain block values from a quadtree decomposition -## -## [vals]=qtgetblk(I,S,dim) returns a dim-by-dim-by-k array in -## @var{vals} which contains the dim-by-dim blocks in the quadtree -## decomposition (@var{S}, which is returned by qtdecomp) of @var{I}. If -## there are no blocks, an empty matrix is returned. -## -## [vals,idx]=qtgetblk(I,S,dim) returns @var{vals} as described above. -## In addition, it returns @var{idx}, a vector which contains the linear -## indices of the upper left corner of each block returned (the same -## result as find(full(S)==dim)). -## -## [vals,r,c]=qtgetblk(I,S,dim) returns @var{vals} as described, and two -## vectors, @var{r} and @var{c}, which contain the row and column -## coordinates of the blocks returned. -## -## @end deftypefn -## @seealso qtdecomp, qtsetblk - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function [varargout] = qtgetblk(I, S, dim) - if (nargin!=3) - usage("[vals,r,c]=qtgetblk(I,S,dim), [vals,idx]=qtgetblk(I,S,dim)"); - endif - if (nargout>3) - usage("[vals,r,c]=qtgetblk(I,S,dim), [vals,idx]=qtgetblk(I,S,dim)"); - endif - - ## get blocks - [i,j,v]=spfind(S); - - ## filter the ones which match dim - idx=find(v==dim); - - if(length(idx)==0) - for i=1:nargout - varargout{i}=[]; - endfor - else - r=i(idx); - c=j(idx); - - ## copy to a dim-by-dim-by-k array - vals=zeros(dim,dim,length(idx)); - for i=1:length(idx) - vals(:,:,i)=I(r(i):r(i)+dim-1,c(i):c(i)+dim-1); - endfor - - varargout{1}=vals; - - if(nargout==3) - varargout{2}=r; - varargout{3}=c; - elseif(nargout==2) - varargout{2}=(c-1)*rows(I)+r; - endif - endif -endfunction - - -%!demo -%! [vals,r,c]=qtgetblk(eye(4),qtdecomp(eye(4)),2) -%! % Returns 2 blocks, at [1,3] and [3,1] (2*2 zeros blocks) - -%!shared A,S -%! A=[ 1, 4, 2, 5,54,55,61,62; -%! 3, 6, 3, 1,58,53,67,65; -%! 3, 6, 3, 1,58,53,67,65; -%! 3, 6, 3, 1,58,53,67,65; -%! 23,42,42,42,99,99,99,99; -%! 27,42,42,42,99,99,99,99; -%! 23,22,26,25,99,99,99,99; -%! 22,22,24,22,99,99,99,99]; -%! S=qtdecomp(A,10); - -%!test -%! [va]=qtgetblk(A,S,8); -%! [vb,r,c]=qtgetblk(A,S,8); -%! [vc,i]=qtgetblk(A,S,8); -%! assert(va, vb); -%! assert(va, vc); -%! assert(i,[]); -%! assert(r,[]); -%! assert(c,[]); -%! R=[]; -%! assert(va,R); - - -%!test -%! [va]=qtgetblk(A,S,4); -%! [vb,r,c]=qtgetblk(A,S,4); -%! [vc,i]=qtgetblk(A,S,4); -%! assert(va, vb); -%! assert(va, vc); -%! assert(i, find(full(S)==4)); -%! assert(r,[1;5]); -%! assert(c,[1;5]); -%! R=zeros(4,4,2); -%! R(:,:,1)=A(1:4,1:4); -%! R(:,:,2)=A(5:8,5:8); -%! assert(va,R); - -%!test -%! [va]=qtgetblk(A,S,2); -%! [vb,r,c]=qtgetblk(A,S,2); -%! [vc,i]=qtgetblk(A,S,2); -%! assert(va, vb); -%! assert(va, vc); -%! assert(i, find(full(S)==2)); -%! assert(r,[7;5;7;1;3;1;3]); -%! assert(c,[1;3;3;5;5;7;7]); -%! R=zeros(2,2,7); -%! R(:,:,1)=A(7:8,1:2); -%! R(:,:,2)=A(5:6,3:4); -%! R(:,:,3)=A(7:8,3:4); -%! R(:,:,4)=A(1:2,5:6); -%! R(:,:,5)=A(3:4,5:6); -%! R(:,:,6)=A(1:2,7:8); -%! R(:,:,7)=A(3:4,7:8); -%! assert(va,R); - -% -% $Log$ -% Revision 1.3 2006/01/02 20:53:42 pkienzle -% Reduce number of shared variables in tests -% -% Revision 1.2 2004/08/11 19:52:41 jmones -% qtsetblk added -% -%
deleted file mode 100644 --- a/qtsetblk.m +++ /dev/null @@ -1,102 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{J} = } qtsetblk (@var{I},@var{S},@var{dim},@var{vals}) -## Set block values in a quadtree decomposition -## -## J=qtsetblk(I,S,dim,vals) sets all the @var{dim}-by-@var{dim} blocks -## in the quadtree decomposition (@var{S} returned by qtdecomp) of -## @var{I} to @var{dim}-by-@var{dim} blocks in @var{vals}, which is -## itself a @var{dim}-by-@var{dim}-by-k array. k is the number of -## @var{dim}-by-@var{dim} blocks in the quadtree decomposition. -## @end deftypefn -## @seealso qtdecomp, qtgetblk - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function J = qtsetblk(I, S, dim, vals) - if (nargin!=4) - usage("J=qtsetblk(I,S,dim,vals)"); - endif - - ## get blocks - [ii,ji,v]=spfind(S); - - ## filter the ones which match dim - idx=find(v==dim); - if(size(vals,3)<length(idx)) ## we won't complain if k>num blocks - error("qtsetblk: k (vals 3rd dimension) is not equal to number of blocks."); - endif - ii=ii(idx); - ji=ji(idx); - - ## calc end vertex - ie=ii+dim-1; - je=ji+dim-1; - - - J=I; - for b=1:length(idx) - J(ii(b):ie(b),ji(b):je(b))=vals(:,:,b); - endfor -endfunction - - -%!demo -%! J=qtsetblk(eye(4),qtdecomp(eye(4)),2,ones(2,2,2)) -%! % Sets upper-right and lower-left blocks of 2*2 zeros to ones - -%!shared A, S -%! A=[ 1, 4, 2, 5,54,55,61,62; -%! 3, 6, 3, 1,58,53,67,65; -%! 3, 6, 3, 1,58,53,67,65; -%! 3, 6, 3, 1,58,53,67,65; -%! 23,42,42,42,99,99,99,99; -%! 27,42,42,42,99,99,99,99; -%! 23,22,26,25,99,99,99,99; -%! 22,22,24,22,99,99,99,99]; -%! S=qtdecomp(A,10); - -%!test -%! R=A; -%! vals=zeros(4,4,2); -%! vals(:,:,1)=reshape([1:16],4,4); -%! vals(:,:,2)=reshape([21:36],4,4); -%! R(1:4,1:4)=reshape([1:16],4,4); -%! R(5:8,5:8)=reshape([21:36],4,4); -%! assert(qtsetblk(A,S,4,vals),R); - -%!test -%! R=A; -%! R(1:4,5:8)=1; -%! R(7:8,1:4)=1; -%! R(5:6,3:4)=1; -%! assert(qtsetblk(A,S,2,ones(2,2,7)),R); - -%!test -%! R=A; -%! R(5:6,1:2)=10; -%! assert(qtsetblk(A,S,1,ones(1,1,4)*10),R); - - - -% -% $Log$ -% Revision 1.1 2004/08/11 19:52:41 jmones -% qtsetblk added -% -%
deleted file mode 100644 --- a/rainbow.m +++ /dev/null @@ -1,56 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} rainbow (@var{n}) -## Create color colormap. -## (red through orange, yellow, green, blue to violet) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = rainbow (number) -## this colormap is not part of matlab, it is like the prism -## colormap map but with a continuous map - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("rainbow: argument must be a scalar"); - endif - else - usage ("rainbow (number)"); - endif - - if (number == 1) - map = [1, 0, 0]; - elseif (number > 1) - x = linspace (0, 1, number)'; - r = (x < 2/5) + (x >= 2/5 & x < 3/5) .* (-5 * x + 3)\ - + (x >= 4/5) .* (10/3 * x - 8/3); - g = (x < 2/5) .* (5/2 * x) + (x >= 2/5 & x < 3/5)\ - + (x >= 3/5 & x < 4/5) .* (-5 * x + 4); - b = (x >= 3/5 & x < 4/5) .* (5 * x - 3) + (x >= 4/5); - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/rgb2gray.m +++ /dev/null @@ -1,47 +0,0 @@ -## Copyright (C) 2000, 2001 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{I}= rgb2gray (@var{M}) -## converts a color map to a gray map. -## The RGB map is converted into the YIQ space of ntsc. The luminance -## value (Y) is taken to create a gray color map. -## R = G = B = Y -## @end deftypefn - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 19. March 2000 - -function graymap = rgb2gray (rgb) - - if (nargin != 1) - usage ("graymap = rgb2gray (map)"); - endif - - msg = "rgb2gray: argument must be a matrix of size n x 3"; - if (! is_matrix (rgb)) - error (msg); - endif - - nc = columns (rgb); - if (nc != 3) - error (msg); - endif - - ntscmap = rgb2ntsc (rgb); - - graymap = ntscmap (:, 1) * ones (1, 3); -endfunction
deleted file mode 100644 --- a/roicolor.m +++ /dev/null @@ -1,74 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{BW} = } roicolor (@var{A},@var{low},@var{high}) -## @deftypefnx {Function File} {@var{BW} = } roicolor (@var{A},@var{v}) -## Select a Region Of Interest of an image based on color. -## -## BW = roicolor(A,low,high) selects a region of interest (ROI) of an -## image @var{A} returning a black and white image in a logical array (1 for -## pixels inside ROI and 0 outside ROI), which is formed by all pixels -## whose values lie within the colormap range specified by [@var{low} -## @var{high}]. -## -## BW = roicolor(A,v) selects a region of interest (ROI) formed by all -## pixels that match values in @var{v}. -## @end deftypefn - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function BW = roicolor(A, p1, p2) - if (nargin < 2 || nargin > 3) - usage("BW = roicolor(A, low, high), BW = roicolor(A, v)"); - endif - - if (nargin == 2) - if (!isvector(p1)) - error("BW = roicolor(A, v): v should be a vector."); - endif - BW=logical(zeros(size(A))); - for c=p1 - BW|=(A==c); - endfor - elseif (nargin==3) - if (!isscalar(p1) || !isscalar(p2)) - error("BW = roicolor(A, low, high): low and high must be scalars."); - endif - BW=logical((A>=p1)&(A<=p2)); - endif -endfunction - -%!demo -%! roicolor([1:10],2,4); -%! % Returns '1' where input values are between 2 and 4 (both included). - -%!assert(roicolor([1:10],2,4),logical([0,1,1,1,zeros(1,6)])); -%!assert(roicolor([1,2;3,4],3,3),logical([0,0;1,0])); -%!assert(roicolor([1,2;3,4],[1,4]),logical([1,0;0,1])); - -% -% $Log$ -% Revision 1.3 2004/09/15 17:54:59 pkienzle -% test that data type matches during assert -% -% Revision 1.2 2004/08/11 15:04:59 pkienzle -% Convert dos line endings to unix line endings -% -% Revision 1.1 2004/08/08 21:02:44 jmones -% Add roicolor function (selects ROI based on color) -% -%
deleted file mode 100644 --- a/rotate_scale.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * ROTATE_SCALE: rotate and scale a matrix using bilinear interpolation - * imo= block(im, xregs, yregs); - * - * Copyright (C) 2003 Andy Adler - * This code has no warrany whatsoever. - * Do what you like with this code as long as you - * leave this copyright in place. - * - * $Id$ - */ - -#include <octave/oct.h> - -void -calc_rotation_params( - double x0l,double y0l,double x0r,double y0r, - double x1l,double y1l,double x1r,double y1r, - double* Tx_x, double* Ty_x, - double* Tx_y, double* Ty_y, - double* Tx_1, double* Ty_1 ); -void -do_interpolation ( - double Tx_x, double Ty_x, - double Tx_y, double Ty_y, - double Tx_1, double Ty_1, - int x0max, int y0max,// initial size - int x1max, int y1max,// output size - const double * img0, - double * img1 ); - -DEFUN_DLD (rotate_scale, args, , - "ROTATE_SCALE: arbitrary rotation and scaling of an image\n" - " using fast bilinear interpolation\n" - "im1 = rotate_scale(im0, lm0, lm1, out_size)\n" - " where:\n" - "im0 = input image\n" - "lm0 = landmarks of points in original image [ x1,x2;y1,y2 ]\n" - "im1 = output image, where size(im1) == out_size\n" - "lm1 = landmarks of points in output image [ x1,x2;y1,y2 ]\n" - "\n" - " note1: two landmarks must be specified for lm0 and lm1\n" - " note2: all images have a single component\n" - " to use this for colour images, use:\n" - " r_im1= rotate_scale( red_im0, lm0, lm1, out_size)\n" - " g_im1= rotate_scale( grn_im0, lm0, lm1, out_size)\n" - " b_im1= rotate_scale( blu_im0, lm0, lm1, out_size)\n" - "\n" - " example:\n" - " im0= zeros(100); im0(25:75,25:75)=1;\n" - " im1= rotate_scale( im0, [40,60;50,50],[60,90;60,90],[120,120]);\n" -) -{ - octave_value_list retval; - if (args.length() < 4 || - !args(0).is_matrix_type() || - !args(1).is_matrix_type() || - !args(2).is_matrix_type() || - !args(3).is_matrix_type() - ) { - print_usage (); - return retval; - } - - Matrix im0( args(0).matrix_value() ); - const double * im0p = im0.data(); - Matrix lm0( args(1).matrix_value() ); - Matrix lm1( args(2).matrix_value() ); - ColumnVector out_size( args(3).vector_value() ); - - int inp_hig= im0.rows(); - int inp_wid= im0.cols(); - - int out_hig= (int) out_size(0); - int out_wid= (int) out_size(1); - Matrix im1( out_hig, out_wid); - double * im1p = im1.fortran_vec(); - - double Tx_x; double Ty_x; - double Tx_y; double Ty_y; - double Tx_1; double Ty_1; - calc_rotation_params( - lm0(0,0), lm0(1,0), lm0(0,1), lm0(1,1), - lm1(0,0), lm1(1,0), lm1(0,1), lm1(1,1), - & Tx_x, & Ty_x, - & Tx_y, & Ty_y, - & Tx_1, & Ty_1 ); - - do_interpolation( Tx_x, Ty_x, Tx_y, Ty_y, Tx_1, Ty_1, - inp_wid, inp_hig, out_wid, out_hig, - im0p, im1p ); - - retval(0) = im1; - return retval; -} - -inline double sqr(double a) { return (a)*(a); } - -void -calc_rotation_params( - double x1l,double y1l,double x1r,double y1r, - double x0l,double y0l,double x0r,double y0r, - double* Tx_x, double* Ty_x, - double* Tx_y, double* Ty_y, - double* Tx_1, double* Ty_1 - ) -{ - double d0= sqrt( sqr(x0l-x0r) + sqr(y0l-y0r) ); - double d1= sqrt( sqr(x1l-x1r) + sqr(y1l-y1r) ); - double dr= d1/d0; - - double a0= atan2( y0l-y0r , x0l-x0r ); - double a1= atan2( y1l-y1r , x1l-x1r ); - double ad= a1-a0; - double dr_cos_ad= dr*cos(ad); - double dr_sin_ad= dr*sin(ad); - - double x0m= (x0l+x0r)/2; - double y0m= (y0l+y0r)/2; - double x1m= (x1l+x1r)/2; - double y1m= (y1l+y1r)/2; - - *Tx_x= dr_cos_ad; - *Ty_x= dr_sin_ad; - *Tx_y= -dr_sin_ad; - *Ty_y= dr_cos_ad; - *Tx_1= x1m - dr_cos_ad*x0m + dr_sin_ad*y0m; - *Ty_1= y1m - dr_sin_ad*x0m - dr_cos_ad*y0m; -} - - -void -do_interpolation ( - double Tx_x, double Ty_x, - double Tx_y, double Ty_y, - double Tx_1, double Ty_1, - int x0max, int y0max,// initial size - int x1max, int y1max,// output size - const double * img0, - double * img1 - ) -{ - - for (int i=0; i< x1max; i++) { - for (int j=0; j< y1max; j++) { - double x0i= Tx_x * i + Tx_y * j + Tx_1; - double y0i= Ty_x * i + Ty_y * j + Ty_1; - - if ( x0i < 0 ) x0i= 0; - else - if (x0i >= x0max-1 ) x0i= x0max - 1.00001; - - if ( y0i < 0 ) y0i= 0; - else - if (y0i >= y0max-1 ) y0i= y0max - 1.00001; - - int x0idx= (int) x0i; - int y0idx= (int) y0i; - - double frac_r= x0i- x0idx; - double frac_l= 1 - frac_r; - double frac_d= y0i- y0idx; - double frac_u= 1 - frac_d; - - int pix_lu= (y0idx+0) + (x0idx+0) * y0max ; - int pix_ru= (y0idx+0) + (x0idx+1) * y0max ; - int pix_ld= (y0idx+1) + (x0idx+0) * y0max ; - int pix_rd= (y0idx+1) + (x0idx+1) * y0max ; - - img1[ i*y1max + j ]= - frac_l*frac_u* img0[ pix_lu ] + - frac_r*frac_u* img0[ pix_ru ] + - frac_l*frac_d* img0[ pix_ld ] + - frac_r*frac_d* img0[ pix_rd ]; - - } - } -} -
deleted file mode 100644 --- a/spring.m +++ /dev/null @@ -1,51 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} spring (@var{n}) -## Create color colormap. -## (magenta to yellow) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = spring (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("spring: argument must be a scalar"); - endif - else - usage ("spring (number)"); - endif - - if (number == 1) - map = [1, 0, 1]; - elseif (number > 1) - r = ones (number, 1); - g = (0:number - 1)' ./ (number - 1); - b = 1 - g; - map = [r, g, b]; - else - map = []; - endif - -endfunction
new file mode 100644 --- /dev/null +++ b/src/Makeconf.add @@ -0,0 +1,3 @@ +@DEFHAVE_JPEG@ +@DEFHAVE_PNG@ +@DEFHAVE_MAGICKXX@
new file mode 100644 --- /dev/null +++ b/src/Makeconf.base @@ -0,0 +1,92 @@ + +## Makeconf is automatically generated from Makeconf.base and Makeconf.add +## in the various subdirectories. To regenerate, use ./autogen.sh to +## create a new ./Makeconf.in, then use ./configure to generate a new +## Makeconf. + +OCTAVE_FORGE = 1 + +SHELL = @SHELL@ + +canonical_host_type = @canonical_host_type@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ +libdir = @libdir@ +datadir = @datadir@ +infodir = @infodir@ +includedir = @includedir@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALLOCT=octinst.sh + +DESTDIR = + +RANLIB = @RANLIB@ +STRIP = @STRIP@ +LN_S = @LN_S@ +MKOCTLINK = @MKOCTLINK@ +OCTLINK= @OCTLINK@ + +AWK = @AWK@ + +# Most octave programs will be compiled with $(MKOCTFILE). Those which +# cannot use mkoctfile directly can request the flags that mkoctfile +# would use as follows: +# FLAG = $(shell $(MKOCTFILE) -p FLAG) +# The following flags are for compiling programs that are independent +# of Octave. How confusing. +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CPICFLAG = @CPICFLAG@ +CXX = @CXX@ +CXXFLAGS = @CXXFLAGS@ +CXXPICFLAG = @CXXPICFLAG@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FPICFLAG = @FPICFLAG@ + +OCTAVE = @OCTAVE@ +OCTAVE_VERSION = @OCTAVE_VERSION@ +MKOCTFILE = @MKOCTFILE@ -DHAVE_OCTAVE_$(ver) -v +SHLEXT = @SHLEXT@ + +@DEFHAVE_X@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ + +ver = @ver@ +MPATH = @mpath@ +OPATH = @opath@ +XPATH = @xpath@ +ALTMPATH = @altmpath@ +ALTOPATH = @altopath@ + +HAVE_DO_FORTRAN_INDEXING = @HAVE_DO_FORTRAN_INDEXING@ +HAVE_PROPAGATE_EMPTY_MATRICES = @HAVE_PROPAGATE_EMPTY_MATRICES@ +HAVE_OK_TO_LOSE_IMAGINARY_PART = @HAVE_OK_TO_LOSE_IMAGINARY_PART@ +HAVE_ND_ARRAYS = @HAVE_ND_ARRAYS@ +TYPEID_HAS_CLASS = @TYPEID_HAS_CLASS@ +CLASS_HAS_LOAD_SAVE = @CLASS_HAS_LOAD_SAVE@ +HAVE_OCTAVE_MAP_INDEX = @HAVE_OCTAVE_MAP_INDEX@ +HAVE_OCTAVE_CONCAT = @HAVE_OCTAVE_CONCAT@ +HAVE_SWAP_BYTES = @HAVE_SWAP_BYTES@ +HAVE_OCTAVE_UPLUS = @HAVE_OCTAVE_UPLUS@ + +MAKEINFO = @MAKEINFO@ +TEXI2DVI = @TEXI2DVI@ +TEXI2HTML = @TEXI2HTML@ +DVIPDF = @DVIPDF@ +DVIPS = @DVIPS@ + +MKDOC = @MKDOC@ +MKTEXI = @MKTEXI@ + +%.o: %.c ; $(MKOCTFILE) -c $< +%.o: %.f ; $(MKOCTFILE) -c $< +%.o: %.cc ; $(MKOCTFILE) -c $< +%.oct: %.cc ; $(MKOCTFILE) $<
new file mode 100644 --- /dev/null +++ b/src/Makeconf.in @@ -0,0 +1,95 @@ + +## Makeconf is automatically generated from Makeconf.base and Makeconf.add +## in the various subdirectories. To regenerate, use ./autogen.sh to +## create a new ./Makeconf.in, then use ./configure to generate a new +## Makeconf. + +OCTAVE_FORGE = 1 + +SHELL = @SHELL@ + +canonical_host_type = @canonical_host_type@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +mandir = @mandir@ +libdir = @libdir@ +datadir = @datadir@ +infodir = @infodir@ +includedir = @includedir@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALLOCT=octinst.sh + +DESTDIR = + +RANLIB = @RANLIB@ +STRIP = @STRIP@ +LN_S = @LN_S@ +MKOCTLINK = @MKOCTLINK@ +OCTLINK= @OCTLINK@ + +AWK = @AWK@ + +# Most octave programs will be compiled with $(MKOCTFILE). Those which +# cannot use mkoctfile directly can request the flags that mkoctfile +# would use as follows: +# FLAG = $(shell $(MKOCTFILE) -p FLAG) +# The following flags are for compiling programs that are independent +# of Octave. How confusing. +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CPICFLAG = @CPICFLAG@ +CXX = @CXX@ +CXXFLAGS = @CXXFLAGS@ +CXXPICFLAG = @CXXPICFLAG@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +FPICFLAG = @FPICFLAG@ + +OCTAVE = @OCTAVE@ +OCTAVE_VERSION = @OCTAVE_VERSION@ +MKOCTFILE = @MKOCTFILE@ -DHAVE_OCTAVE_$(ver) -v +SHLEXT = @SHLEXT@ + +@DEFHAVE_X@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ + +ver = @ver@ +MPATH = @mpath@ +OPATH = @opath@ +XPATH = @xpath@ +ALTMPATH = @altmpath@ +ALTOPATH = @altopath@ + +HAVE_DO_FORTRAN_INDEXING = @HAVE_DO_FORTRAN_INDEXING@ +HAVE_PROPAGATE_EMPTY_MATRICES = @HAVE_PROPAGATE_EMPTY_MATRICES@ +HAVE_OK_TO_LOSE_IMAGINARY_PART = @HAVE_OK_TO_LOSE_IMAGINARY_PART@ +HAVE_ND_ARRAYS = @HAVE_ND_ARRAYS@ +TYPEID_HAS_CLASS = @TYPEID_HAS_CLASS@ +CLASS_HAS_LOAD_SAVE = @CLASS_HAS_LOAD_SAVE@ +HAVE_OCTAVE_MAP_INDEX = @HAVE_OCTAVE_MAP_INDEX@ +HAVE_OCTAVE_CONCAT = @HAVE_OCTAVE_CONCAT@ +HAVE_SWAP_BYTES = @HAVE_SWAP_BYTES@ +HAVE_OCTAVE_UPLUS = @HAVE_OCTAVE_UPLUS@ + +MAKEINFO = @MAKEINFO@ +TEXI2DVI = @TEXI2DVI@ +TEXI2HTML = @TEXI2HTML@ +DVIPDF = @DVIPDF@ +DVIPS = @DVIPS@ + +MKDOC = @MKDOC@ +MKTEXI = @MKTEXI@ + +%.o: %.c ; $(MKOCTFILE) -c $< +%.o: %.f ; $(MKOCTFILE) -c $< +%.o: %.cc ; $(MKOCTFILE) -c $< +%.oct: %.cc ; $(MKOCTFILE) $< +@DEFHAVE_JPEG@ +@DEFHAVE_PNG@ +@DEFHAVE_MAGICKXX@
new file mode 100644 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,37 @@ +sinclude Makeconf + +ifdef HAVE_JPEG + JPEG=jpgwrite.oct jpgread.oct +endif + +ifdef HAVE_PNG + PNG=pngread.oct pngwrite.oct +endif + +ifdef HAVE_MAGICKXX + IMAGEMAGICK=__imagemagick__.oct __magick_read__$(OCTLINK) +endif + +all: cordflt2.oct bwlabel.oct bwfill.oct rotate_scale.oct \ + houghtf.oct graycomatrix.oct \ + $(JPEG) $(PNG) $(IMAGEMAGICK) + +jpgread.oct: jpgread.cc + $(MKOCTFILE) $< -ljpeg + +jpgwrite.oct: jpgwrite.cc + $(MKOCTFILE) $< -ljpeg + +pngread.oct: pngread.cc + $(MKOCTFILE) $< -lpng + +pngwrite.oct: pngwrite.cc + $(MKOCTFILE) $< -lpng + +__imagemagick__.oct: __imagemagick__.cc + $(MKOCTFILE) $< -lMagick++ -lMagick + +__magick_read__$(OCTLINK): __imagemagick__.oct + $(MKOCTLINK) __imagemagick__.oct $@ + +clean: ; -$(RM) *.o octave-core core *.oct *~
new file mode 100644 --- /dev/null +++ b/src/__imagemagick__.cc @@ -0,0 +1,310 @@ +#include <octave/oct.h> +#include <Magick++.h> +#include <iostream> +using namespace std; +using namespace Magick; + +octave_value_list read_indexed_images(vector<Image> imvec, Array<int> frameidx, bool wantalpha) +{ + octave_value_list output; + int rows = imvec[0].baseRows(); + int columns = imvec[0].baseColumns(); + int nframes = frameidx.length(); + ImageType type = imvec[0].type(); + + unsigned int mapsize = imvec[0].colorMapSize(); + int i = mapsize; + unsigned int depth = 0; + while(i >>= 1) depth++; + i = 0; + depth--; + while(depth >>= 1) i++; + depth = 1 << i; + + int x, y, frame; + const IndexPacket *pix; + switch(depth) { + case 1: + case 2: + case 4: + case 8: + { + uint8NDArray im = uint8NDArray(dim_vector(rows, columns, nframes)); + for(frame=0; frame < nframes; frame++) { + imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); + pix = imvec[frameidx(frame)].getConstIndexes(); + i = 0; + for(y=0; y < rows; y++) { + for(x=0; x < columns; x++) { + im(y, x, frame) = static_cast<octave_uint8>(pix[i++]); + } + } + } + im.chop_trailing_singletons(); + output(0) = octave_value(im); + } + break; + case 16: + { + uint16NDArray im = uint16NDArray(dim_vector(rows, columns, nframes)); + for(frame=0; frame < nframes; frame++) { + imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); + pix = imvec[frameidx(frame)].getConstIndexes(); + i = 0; + for(y=0; y < rows; y++) { + for(x=0; x < columns; x++) { + im(y, x, frame) = static_cast<octave_uint16>(pix[i++]); + } + } + } + im.chop_trailing_singletons(); + output(0) = octave_value(im); + } + break; + default: + error("Index depths bigger than 16-bit not supported"); + return octave_value_list(); + } + + ColorRGB c; + Matrix map = Matrix(mapsize, 3); + Matrix alpha; + switch(type) { + case PaletteMatteType: +/* warning("palettematte"); + map = Matrix(mapsize, 3); + alpha = Matrix(mapsize, 1); + for(i = 0; i < mapsize; i++) { + warning("%d", i); + c = imvec[0].colorMap(i); + map(i, 0) = c.red(); + map(i, 1) = c.green(); + map(i, 2) = c.blue(); + alpha(i, 1) = c.alpha(); + } + break; */ + case PaletteType: + alpha = Matrix(0,0); + for(i = 0; i < mapsize; i++) { + c = imvec[0].colorMap(i); + map(i, 0) = c.red(); + map(i, 1) = c.green(); + map(i, 2) = c.blue(); + } + break; + default: + error("Unsupported indexed image type"); + return octave_value_list(); + } + + output(1) = octave_value(map); + if(wantalpha) { + output(2) = octave_value(alpha); + } + return output; +} + +template <class T> +octave_value_list read_images(vector<Image> imvec, Array<int> frameidx) +{ + int i; + T im; + int rows = imvec[0].baseRows(); + int columns = imvec[0].baseColumns(); + int nframes = frameidx.length(); + ImageType type = imvec[0].type(); + + int x, y, frame; + const PixelPacket *pix; + dim_vector idim = dim_vector(); + idim.resize(4); + idim(0) = rows; + idim(1) = columns; + idim(2) = 1; + idim(3) = nframes; + Array<int> idx(dim_vector(4)); + switch(type) { + case BilevelType: + // break; + case GrayscaleType: + im = T(dim_vector(rows, columns, nframes)); + for(frame=0; frame < nframes; frame++) { + pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); + i = 0; + for(y=0; y < rows; y++) { + for(x=0; x < columns; x++) { + im(y, x, frame) = pix[i++].red; + } + } + } + break; + case GrayscaleMatteType: + idim(2) = 2; + im = T(idim); + for(frame=0; frame < nframes; frame++) { + idx(3) = frame; + i = 0; + pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); + for(y=0; y < rows; y++) { + idx(0) = y; + for(x=0; x < columns; x++) { + idx(1) = x; + idx(2) = 0; + im(idx) = pix[i].red; + idx(2) = 1; + im(idx) = pix[i].opacity; + i++; + } + } + } + break; + case PaletteType: + case TrueColorType: + idim(2) = 3; + im = T(idim); + for(frame=0; frame < nframes; frame++) { + idx(3) = frame; + i = 0; + pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); + for(y=0; y < rows; y++) { + idx(0) = y; + for(x=0; x < columns; x++) { + idx(1) = x; + idx(2) = 0; + im(idx) = pix[i].red; + idx(2) = 1; + im(idx) = pix[i].green; + idx(2) = 2; + im(idx) = pix[i].blue; + i++; + } + } + } + break; + case PaletteMatteType: + case TrueColorMatteType: + case ColorSeparationType: + idim(2) = 4; + im = T(idim); + for(frame=0; frame < nframes; frame++) { + idx(3) = frame; + i = 0; + pix = imvec[frameidx(frame)].getConstPixels(0,0, columns, rows); + for(y=0; y < rows; y++) { + idx(0) = y; + for(x=0; x < columns; x++) { + idx(1) = x; + idx(2) = 0; + im(idx) = pix[i].red; + idx(2) = 1; + im(idx) = pix[i].green; + idx(2) = 2; + im(idx) = pix[i].blue; + idx(2) = 3; + im(idx) = pix[i].opacity; + i++; + } + } + } + break; + default: + error("Undefined Imagemagick image type"); + return octave_value_list(); + } + + im.chop_trailing_singletons(); + return octave_value_list(octave_value(im)); +} + +// instantiate templates +template octave_value_list read_images<boolNDArray>(vector<Image>, Array<int>); +template octave_value_list read_images<uint8NDArray>(vector<Image>, Array<int>); +template octave_value_list read_images<uint16NDArray>(vector<Image>, Array<int>); + +DEFUN_DLD(__magick_read__, args, nargout, +"function m = __imagemagick_read__(fname[, index])\n\ +function [m, colormap] = __imagemagick_read__(fname[, index])\n\ +function [m, colormap, alpha] = __imagemagick_read__(fname[, index])\n\ +\n\ +Read images with ImageMagick++. User interface in imread.m.\n\ +\n\ +") +{ + octave_value_list output; + int i; + if(args.length() > 2 || args.length() < 1 || !args(0).is_string() \ + || nargout > 3) { + print_usage (); + return octave_value_list(); + } + Array<int> frameidx; + if(args.length() == 2 && args(1).is_real_type()) { + frameidx = args(1).int_vector_value(); + } else { + frameidx = Array<int>(1); + frameidx(0) = 1; + } + + vector<Image> imvec; + try { + // Read a file into vector of image objects + readImages(&imvec, args(0).string_value()); + } + catch( Warning &warning_ ) { + warning("Magick++ warning: %s", warning_.what()); + } + catch( ErrorCoder &error_) { + warning("Magick++ coder error: %s", error_.what()); + } + catch( Exception &error_ ) { + error("Magick++ exception: %s", error_.what()); + imvec.clear(); + return octave_value_list(); + } + + int nframes = imvec.size(); + for(i = 0; i < frameidx.length(); i++) { + frameidx(i) = frameidx(i) - 1; + if(frameidx(i) >= nframes || frameidx(i) < 0) { + error("Invalid index vector"); + imvec.clear(); + return output; + } + } + + ClassType klass = imvec[0].classType(); + if(klass == PseudoClass && nargout > 1) { + output = read_indexed_images(imvec, frameidx, (nargout == 3)); + } else { + int depth = imvec[0].modulusDepth(); + i = 0; + while(depth >>= 1) i++; + depth = 1 << i; + + switch(depth) { + case 1: + output = read_images<boolNDArray>(imvec, frameidx); + break; + case 2: + case 4: + case 8: + output = read_images<uint8NDArray>(imvec, frameidx); + break; + case 16: + output = read_images<uint16NDArray>(imvec, frameidx); + break; + case 32: + case 64: + default: + error("Image depths bigger than 16-bit not supported"); + } + if(nargout > 1) { + output(1) = Matrix(0,0); + if(nargout > 2) + output(2) = Matrix(0,0); + } + } + imvec.clear(); + + return output; +}
new file mode 100644 --- /dev/null +++ b/src/admin/CONTENTS @@ -0,0 +1,3 @@ +Contains files and scripts used to administer the octave-forge +website and build the release files. Nothing in here is needed +by octave-forge users.
new file mode 100644 --- /dev/null +++ b/src/admin/OctRe.pm @@ -0,0 +1,101 @@ +#!/usr/bin/perl -w + +=head1 NAME OctRe - Regexes for octave code + +Regexpes come in pairs, I<$XYZ_re>,which don't set I<$1, $2, ...> +and I<$XYZ_rx>, which do. + +=over 4 + +=item I<$var_r[ex]> match an octave variable (sets I<$1>) + +=item I<$dot_r[ex]> match an ellipsis (sets I<$1>) + +=item I<$vl_r[ex]> match a variable list, as it appears in a function +call (sets I<$1>). The individual variables in $1 can be retrieved +with /$var_rx/g. Example : "x, y, z". + +=item I<retl_r[xe]> match a return list, as it appears in a function +declaration (sets I<$1>). The individual variables in $1 can be +retrieved with /$var_rx/g. Example : "[x]", "[ x, y]", "[x,y,z]", +"[x,...]". + +=item I<retl_r[xe]> match an argument list, as it appears in a +function declaration (sets I<$1>). The individual variables in $1 can +be retrieved with /$var_rx/g. Example : "(x)", "( x, y)", "(x,y,z)", +"(x,...)". + +=back + +Rem : This is not a true module, as no package is used. It just declares +some regexes. + +=cut + +## Variable $1 : variable name +$var_re = qr{\s*[A-Za-z\_]+\w*\s*} ; +$var_rx = qr{\s*([A-Za-z\_]+\w*)\s*} ; + +## Ellipsis $1 : ellipsis +$dot_re = qr{\.\.\.} ; +$dot_rx = qr{(\.\.\.)} ; # qr{(${var_re})(?:\,(${var_re}))*} ; + +## Variable list : $1, $2 ... variable names +$vl_re = qr{${var_re}(?:\,${var_re})*} ; +$vl_rx = qr{(${var_re})(?:\,(${var_re}))*} ; + +## Return list (as in function declaration) +## $1, $2 ... : variable names (or ellipsis at end) +$retl_re = qr{(?:\[\s*(?:${vl_re}(?:,$dot_re)?|$dot_re|)\s*\]|${var_re})\s*\=|} ; +$retl_rx = qr{(?:\[\s*(?:${vl_rx}(?:,$dot_rx)?|$dot_rx|)\s*\]|${var_rx})\s*\=|} ; + +# Simple assignment $1 : lhs name +$sas_re = qr{${var_re}\s*\=} ; +$sas_rx = qr{${var_rx}\s*\=} ; + +## Return list, as in function call. Call it "mas" like multiple +## assignment. +# $1, $2, ... : variable names +$mas_re = qr{(?:\[(?:${vl_re})\]|${var_re})\s*\=} ; +$mas_rx = qr{(?:\[(?:${vl_rx})\]|${var_rx})\s*\=} ; + +## Arg list as in function declaration +## $1, $2, ... : variable names +$argl_re = qr{(?:\((?:${vl_re}(?:,$dot_re)?|$dot_re|)\)|)} ; +$argl_rx = qr{(?:\((?:${vl_rx}(?:,$dot_rx)?|$dot_rx|)\)|)} ; + +## $retl_re = qr{(?:\((?:${vl_re}(?:,$dot_re)?|$dot_re|)\)|)} ; + +## $argl_re = qr{\((?:${var_re}(?:\,${var_re})*)?\)|} ; + +## Function definition +# $1 : return list; $2 : function name; $3 : arg list. +$defun_re = qr{^\s*function\s+${retl_re}\s*${var_re}${argl_re}} ; +$defun_rx = qr{^\s*function\s+(${retl_re})\s*(${var_rx})(${argl_re})} ; +## Two quoting chars +$qch2_re = qr{\\\\} ; + +## Quotes next character +$qch_re = qr{\\${qch2_re}*} ; + +## String +$str_re = qr{\'(?:[^'\n]|(?<!\\)${qch2_re}+\')*\'|\"(?:[^"\n]|(?<!\\)${qch2_re}+\")*\"} ; +$str_rx = qr{(\'(?:[^'\n]|(?<!\\)${qch2_re}+\')*\'|\"(?:[^"\n]|(?<!\\)${qch2_re}+\")*\")} ; + +## Parenthesis " +$oppar = qr{[\(\{\[]}; +$noppar = qr{[^\(\{\[]}; +$opparx = qr{([\(\{\[])}; + +$mcp = {"("=>")", "["=>"]", "{"=>"}"}; + + +## Comments +## Not perfect, but should catch most cases +## $com_re = qr{\#((?:[^'"]|(?<!\\)${qch2_re}*['"])*['"]|.*)} ; + +$cch_re = qr{[\#%]+}; +$cch_rx = qr{([\#%]+)}; + +1; +
new file mode 100644 --- /dev/null +++ b/src/admin/change_va_arg.pm @@ -0,0 +1,48 @@ +#!/usr/bin/perl -w -n + +## defines function change_line that transforms old-style variable argument +## lists (...) into new-style varargin. va_arg() etc are also transformed. + +BEGIN{ + + $va_arg_re = qr!^(\s*function\s*\w*.*?\(.*?)\.\.\.(\s*\).*)$!; + +} + +## Does necessary changes inplace on $_[0]. +sub change_line { + + if ($_[0] !~ /^\s*\#/) { # Don't do obvious comment lines + + # Transform ... in function decalaration + + $_[0] =~ s{$va_arg_re}{$1varargin$2}og; + + # list(all_va_args) becomes varargin + + $_[0] =~ s!list\s*\(\s*all_va_args\s*\)!varargin!og; + + # all_va_args becomes varargin{:} + + $_[0] =~ s!all_va_args!varargin{:}!og; + + # va_start() can be delicate, so add a + # warning. + + # declare a va_arg_cnt counter + + $_[0] =~ s!(.*\b)va_start\b(\s*\(\s*\)|)(.*)!$1va_arg_cnt = 1$3\nwarn ("va_start should be transformed\\n");\n!g; + + # Use that counter to substitute va_arg by + # nth (varargin, va_arg_cnt++) + + $_[0] =~ s!(.*\b)va_arg\b(\s*\(\s*\)|)(.*)!$1nth (varargin, va_arg_cnt++)$3!g; + } +} + +## Does it look like an underlined func that is not a function call? +sub comment_line { + 0 ? + "## Hmmm ... is that a function call?\n" : ""; +} +1;
new file mode 100755 --- /dev/null +++ b/src/admin/find_changes @@ -0,0 +1,172 @@ +#!/usr/bin/perl -w + +=head1 NAME find_changes.pl - Find patterns in text files and propose changes. + +This script passes lines of text through a perl function with the aim of +reporting the occurence of patterns and proposing changes to be +done. L<patch> should be used to actually modify the original files. + +=head1 SYNOPSIS + +find_changes.pl [options] changes_def file(s).txt ... E<gt> changes_patch + +Reads and executes the perl F<changes_def> file, which must contain the +definition of a function called C<change_line()>, and then reads the +F<file(s).txt> line by line. + +For each line of each file, the function F<change_line()> is called with the +line as single argument, which can be modified inplace. + +If any change is done to the line, it is reported by printing to stdout a +universal diff patch. + +=head2 Modifying files + +It is then recommended to inspect and edit the file F<changes_patch>, +removing lines that should not be changed. Once this is done, the changes +can be done in the original files by using C<patch -p0 < changes_patch>. + +=head2 Commenting on lines + +If a function C<comment_line()> is present, each line will be passed to it +and its output will be shown on standard error. + +=head1 OPTIONS + +=over 4 + +=item -p, --patch + +Output a patch (default). + +=item -d + +Use another output format, adapted to some F<do_changes.pl> script. + +=item -v, --verbose + +Print some info on stderr during execution. + +=item -h, --help + +Print a help message and exit. + +=head1 COPYRIGHT + +This file is distributed under the terms of the GNU General Public Licence. + +=head1 AUTHOR Etienne Grossmann E<lt>etienne@isr.ist.utl.ptE<gt> + +=cut + +### +sub help {system ("perldoc $0|cat")} + +$patch = 1; +$verbose = 0; + # Read options + +while (@ARGV && ($ARGV[0] =~ /^\-/)) { + if ($ARGV[0] =~ /^\-(h|\-help)$/){ help(); exit 0;} + elsif ($ARGV[0] =~ /^\-(v|\-verbose)$/){ $verbose = 1;} + elsif ($ARGV[0] =~ /^\-(p|\-patch)$/) { + $patch = 1; + } elsif ($ARGV[0] =~ /^\-(d)$/) { + $patch = 0; + } else { + die "Unknown option '$ARGV[0]'. Try '$0 --help'"; + } + + shift @ARGV; +} + +die "No definition file specified" unless @ARGV; + +$dfile = shift @ARGV; + + # Read and compile definition file +print STDERR "Definition file is $dfile\n" if $verbose; + +if (!defined (do ($dfile))) { + if ($!) { + print STDERR "Can't find $dfile : '$!'\n"; + exit 1; + } elsif ($@) { + print STDERR "Can't compile $dfile : '$@'\n"; + exit 1; + } else { + print STDERR "Problem with $dfile : do returns undefined\n"; + exit 1; + } +} + +if (!defined (&change_line)) { + print STDERR "File '$dfile' does not define a function 'change_line()'\n"; + exit 1; +} + +$has_comment = defined (&comment_line); + +foreach my $f (@ARGV) { + + if (!$patch) { + unless (open FF, "<$f") { + print "## Whoa!!! Can't open file '$f'. Skipping"; + next; + } + print STDERR "Scanning file $f\n" if $verbose; + + + local $lnum = 0; + while (! eof (FF)) { + + my $line = <FF>; # Read a line + my $olin = $line; + $lnum++; + + if ($has_comment) { + if ($comment = &comment_line ($line)) { + $comment = "## $comment" if $comment !~ /^\s*\#/; + $comment .= "\n" if $comment !~ /\n$/; + print "$f:$.:$comment"; + } + } + + &change_line ($line); + if ($olin ne $line) { + print "$f:$.:$olin"; + } + } + close FF; + } else { # Do a patch. Using diff, what else? + my $nf = "$f.new"; + my $i = 1; + while (-e $nf) { # Find a name for the temp file. + $nf = $f . ".new." . $i ; + } + unless (open FF, "<$f") { + print STDERR "## Whoa!!! Can't open file '$f'. Skipping\n"; + } + unless (open GG, ">$nf") { + print STDERR "## Whoa!!! Can't open temp file '$nf'. Skipping\n"; + next; + } + print STDERR "## Scanning file $f\n" if $verbose; + + while (! eof (FF)) { # Create (temp) transformed file + + my $line = <FF>; # Read a line + + &change_line ($line); + print GG $line; + } + close FF; close GG; + # Call diff and modify slightly the output + my $tmp = `diff -u $f $nf`; + $tmp =~ s{^\+\+\+ $nf}{+++ $f}m; + print $tmp; + + unlink($nf) or print STDERR "## Whoa!!! Can't remove temp file '$nf'\n"; + } +} +
new file mode 100755 --- /dev/null +++ b/src/admin/get_authors @@ -0,0 +1,241 @@ +#!/usr/bin/env perl +# +# Traverse the directory tree and extract author information from .m +# files. Put author information in the file 'AUTHORS'. +# Understands variations of these entries: +# +# ## Copyright (C) year(s) name1 <email> +# ## Copyright (C) year(s) name2 <email> +# ## Author: name3 <email> +# ## Author: name4 <email> +# +# Albert Danial Dec 15 2001 +# Nov 30 2002 - Attribute to 'Anonymous' any file which has +# licensing terms (ie, granted to public domain) +# but no author. Show code and comment line +# counts. +# Apr 25 2005 - Added -s option, better logic to identify +# public domain files. +# Dirk Eddelbuettel 07 Jul 2004 also look at .cc files and // comments +# +# Usage: admin/get_authors [-s <# lines>] +# Scans .m and .cc files and extracts author and copyright +# information. Creates the AUTHORS file. +# Option: -s <n> Set the size of a "short" program +# to <n> non-commented lines. +# Copyrights aren't needed for short +# programs. Default <n> is 5. +# +use warnings; +use strict; +use vars qw($opt_s ); +use Cwd; +use Getopt::Std; +use File::Find; + +getopts('s:'); +$opt_s = 5 unless $opt_s; # set the default value +my $location = getcwd; +my $PATH = ""; +if ($location =~ m{^(.*)/admin$}) { + chdir ".."; + $PATH = "$1/"; +} + +my @files = (); # to contain relative path names of each .m file +find(\&wanted, "."); # start here & descend recursively; populate @files + +my %file_data = (); +classify_files(\@files, # in + \%file_data); # out file_data{file}{'name'} = [ names ] + # {'year'} = [ years ] + # {'mail'} = [ email addrs ] + # {'cpyr'} = [ 'C' or ' ' ] + # {'n_code'} = # lines code + # {'n_comment'} = # lines of + # comments + +# traverse file_data and extract +# - files without copyrights +# - files without authors +# - files grouped by author +# - author to email map +# - number of lines of code, number of lines of comments +my @unattributed_files = (); +my @uncopyrighted_files = (); +my @short_files = (); +my @public_domain = (); +my %email = (); # email{ author name } = email address +my %files = (); # files{ author name } = [ list of files ] +foreach my $f (sort @files) { + # each file can have multiple authors, loop over each author + if (!defined @{$file_data{$f}{name}}) { + if ($file_data{$f}{n_code} > $opt_s) { # not a short program + push @unattributed_files, $f; + } else { + push @short_files , $f; + } + next; + } + my $copyrighted = 0; + for (my $i = 0; $i < scalar @{$file_data{$f}{name}}; $i++) { + if (defined $file_data{$f}{mail}[$i]) { + $email{ $file_data{$f}{name}[$i] } = $file_data{$f}{mail}[$i]; + } + if (defined $file_data{$f}{cpyr}[$i]) { + $copyrighted = 1; + push @public_domain, $f if $file_data{$f}{cpyr}[$i] eq "P"; + } + $files{ $file_data{$f}{name}[$i] }{$f} = 1; + } + next if $copyrighted; + if ($file_data{$f}{n_code} > $opt_s) { # then it is not a short program + push @uncopyrighted_files, $f; + } else { + push @short_files , $f; + } +} + +printf "%3d uncopyrighted files:%s lines of code/lines of comments\n", + scalar @uncopyrighted_files, ' ' x 22; +foreach my $f (sort @uncopyrighted_files) { + printf " %-50s %3d/%3d\n", + $f, $file_data{$f}{n_code}, $file_data{$f}{n_comment}; +} + +printf "\n%3d unattributed files:%s lines of code/lines of comments\n", + scalar @unattributed_files, ' ' x 23; +foreach my $f (sort @unattributed_files) { + printf " %-50s %3d/%3d\n", + $f, $file_data{$f}{n_code}, $file_data{$f}{n_comment}; +} + +printf "\n%3d public domain files:%s lines of code/lines of comments\n", + scalar @public_domain, ' ' x 22; +foreach my $f (sort @public_domain) { + printf " %-50s %3d/%3d\n", + $f, $file_data{$f}{n_code}, $file_data{$f}{n_comment}; +} + +printf "\n%3d uncopyrighted short (<= %2d lines) files:%s lines of code/lines of comments\n", + scalar @short_files, $opt_s, ' ' x 2; +foreach my $f (sort @short_files) { + printf " %-50s %3d/%3d\n", + $f, $file_data{$f}{n_code}, $file_data{$f}{n_comment}; +} + +my $Auth_file = "AUTHORS"; +open(OUT, ">$Auth_file") or die "Cannot write $Auth_file: $!\n"; +printf "%3d authors:\n", scalar keys %files; +foreach my $n (sort keys %files) { + printf "%-28s", $n; + printf OUT "%-28s", $n; + print $email{$n} if defined $email{$n}; + print OUT $email{$n} if defined $email{$n}; + print "\n"; + print OUT "\n"; + my $i = 0; + foreach my $f (sort keys %{$files{$n}}) { + printf "%3d. %-50s %3d/%3d\n", + ++$i, $f, $file_data{$f}{n_code}, $file_data{$f}{n_comment}; + } +} +close OUT; +warn "Wrote ${PATH}${Auth_file}\n"; + +# # # # # # # + +#sub by_last_name { # {{{1 for sorting on names +# (my $A = $a) =~ s/.*?(\w+)$/$1/; +# (my $B = $b) =~ s/.*?(\w+)$/$1/; +# return lc($A) cmp lc($B); +#} # 1}}} + +# # # # # # # + +sub classify_files { # {{{1 + my ($ra_files, # in, list of files + $rhha_data, # out, data{file}{ name | year | cpyr } = [entries] + ) = @_; + warn "Found ", scalar grep (/\.m$/, @{$ra_files}), " .m files; ", + scalar grep (/\.cc$/, @{$ra_files}), " .cc files", + "\n"; + foreach my $f (@{$ra_files}) { + open(IN, $f) or die "Cannot read $f: $!\n"; + my $found_copyright = 0; + my $found_author = 0; + $rhha_data->{$f}{n_code} = 0; + $rhha_data->{$f}{n_comment} = 0; + while (<IN>) { + # find the copyright line and extract author info from it + if (/^[#%\/]+/) { # a comment + ++$rhha_data->{$f}{n_comment}; + } elsif (!/^\s*$/) { # not a blank line + ++$rhha_data->{$f}{n_code}; + } + s/all\s+rights\s+reserved\.?//i; + s/\bby\s+//i; + + if (/^\s*[#%\/\*]* # one or more leading comment markers + \s*copyright # Copyright + \s*(\(c\))? # (c) - optional $1 + \s*(\d[,\- 0-9]+) # Year (or years) $2 + \s+(\w.*?) # name $3 + \s*(<.*>)? # email - optional $4 + \s*$/ix) { + $found_copyright = 1; + $found_author = 1; + my $year = $2; + my $name = $3; + $name = "John W. Eaton" if $name eq "jwe"; + $name =~ s/\.\s*$//; # strip trailing period + my $email = "" || $4; + $name =~ s/^\s+//; # strip leading whitespace + $name =~ s/\s+$//; # strip trailing whitespace + push @{$rhha_data->{$f}{name}}, $name; + push @{$rhha_data->{$f}{year}}, $year; + push @{$rhha_data->{$f}{mail}}, $email; + push @{$rhha_data->{$f}{cpyr}}, 'C'; + # don't exit w/last because there could be multiple copyrights + } elsif ( + /^\s*[#%\/\*]* # one or more leading comment markers + \s*author\s*:? # Author + \s+(\w.*?) # name $1 + \s*(<.*>)? # email - optional $2 + \s*$/ix) { + my $name = $1; + $name =~ s/\.\s*$//; # strip trailing period + $name = "John W. Eaton" if $name eq "jwe"; + my $email = "" || $2; + push @{$rhha_data->{$f}{name}}, $name; + push @{$rhha_data->{$f}{year}}, ""; + push @{$rhha_data->{$f}{mail}}, $email; + $found_author = 1; + } elsif ( + /^\s*[#%\/\*]* # one or more leading comment markers + .*? # some leading text + \b(grant(ed)?|place(d)?|give(n)?|is)(\s+this)? + (\s+(file|program|script|code|algorithm))?(\s+(in|to))? + (\s+the)? + \s+public\s+domain + /ix) { + push @{$rhha_data->{$f}{cpyr}}, 'P'; + $found_copyright = 1; + } + } + if ($found_copyright and !$found_author) { + push @{$rhha_data->{$f}{name}}, "Anonymous"; + push @{$rhha_data->{$f}{year}}, ""; + push @{$rhha_data->{$f}{mail}}, ""; + push @{$rhha_data->{$f}{cpyr}}, 'C'; + } + close IN; + } +} # 1}}} + +# # # # # # # + +sub wanted { # {{{1 populates global array @files + return unless -f and /\.(m|cc)$/; # only want .m files (for now) + push @files, "$File::Find::name"; +} # 1}}}
new file mode 100755 --- /dev/null +++ b/src/admin/get_contents @@ -0,0 +1,181 @@ +#!/usr/bin/env perl +# +# Traverse the directory tree and look for files called 'CONTENTS'. +# Insert the text from these files into octave-forge documentation +# files such as the top-level README, and the developer's guide. +# Issues: +# - Entries in the README appear in the sort order of +# the directory names the CONTENTS files are in. This +# isn't necessarily the best sequence since some directories +# such as main/ should appear first. +# - At the moment the text in the CONTENTS files should be plain +# text. Planning to allow texinfo for layout control in .html +# files. +# +# Albert Danial Jan 2 2002 + +use strict; +use File::Find; + +my $location = `pwd`; +my $PATH = ""; +if ($location =~ m{^(.*)/admin$}) { + chdir ".."; + $PATH = "$1/"; +} + +my @files = (); # to contain relative path names of each CONTENTS file +find(\&wanted, "."); # start here & descend recursively; populate @files + +fill_README(@files); # creates 'README' from 'template.readme' +fill_developer_html(@files); # creates 'new_developer.html' from 'template.ndev' + +# # # # # # # + +sub fill_README { # {{{1 + my (@files, ) = @_; + my $template = "admin/template.readme"; # -> reads + my $RM = "README"; # -> writes + if (!-r $template) { + warn "Unable to read the file '$template'; cannot make README\n"; + return; + } + open(IN, $template) or die "Unable to read $template: $!\n"; + my @template_data = <IN>; # slurp the entire file + close IN; + + my $added_contents = 0; + my $top_of_file = 1; + open(README, ">$RM") or die "Unable to write $RM: $!\n"; + foreach my $t (@template_data) { + if ($top_of_file) { # skip over warning lines in + next if $t =~ /^-> /; # template starting with '->' + $top_of_file = 0; + } elsif ($added_contents) { + print README $t; + next; + } elsif ($t =~ /^Project organization/) { + print README "$t\n"; + foreach (sort @files) { + open(CONTENTS, $_) or die "Cannot read $_: $!\n"; + my @c = <CONTENTS>; + close CONTENTS; + m{^(.*)/(.*?)$}; # match directory and file's basename + my $dir = $1; + my $file = $2; + $dir =~ s{^\./}{}; # strip leading ./ + print README "$dir/\n"; + foreach my $line (@c) { + print README "\t$line"; + } + print README "\n"; + } + $added_contents = 1; + } else { + print README $t; + } + } + close README; + warn "Use 'cvs diff ${PATH}${RM}' to determine if updates are needed.\n"; + warn "Use 'cvs commit ${PATH}${RM}' to update README.\n"; +} # 1}}} + +# # # # # # # + +sub fill_developer_html { # {{{1 + my (@files, ) = @_; + my $template = "admin/template.ndev"; # <- reads + my $RM = "doc/new_developer.html"; # <- writes + if (!-r $template) { + warn "Unable to read the file '$template'; cannot make README\n"; + return; + } + open(IN, $template) or die "Unable to read $template: $!\n"; + my @template_data = <IN>; # slurp the entire file + close IN; + + my $added_contents = 0; + my $top_of_file = 1; + open(README, ">$RM") or die "Unable to write $RM: $!\n"; + foreach my $t (@template_data) { + if ($top_of_file) { # skip over warning lines in + next if $t =~ /^-> /; # template starting with '->' + $top_of_file = 0; + } elsif ($added_contents) { + print README $t; + next; + } elsif ($t =~ /^>>>INSERT CONTENTS HERE<<</) { + foreach (sort @files) { + open(CONTENTS, $_) or die "Cannot read $_: $!\n"; + my @c = <CONTENTS>; + close CONTENTS; + text_bullet_list_to_HTML(\@c); + m{^(.*)/(.*?)$}; # match directory and file's basename + my $dir = $1; + my $file = $2; + $dir =~ s{^\./}{}; # strip leading ./ + print README "\t<li> <b><tt>$dir/</tt></b><br>\n"; + foreach my $line (@c) { + # use fixed font for words that end with / + # (ie, directory names). + $line =~ s{\s(\S+/)([.,\s])}{ <tt>$1</tt>$2}g; + print README "\t$line"; + } + print README "\n"; + } + $added_contents = 1; + } else { + print README $t; + } + } + close README; + warn "Use 'scp ${PATH}${RM} \$OFHOME' to update the web.\n"; +} # 1}}} + +# # # # # # # + +sub text_bullet_list_to_HTML { # {{{1 + # Takes an array of plain text lines and embeds <ul>, <li>, and </ul> + # tags as appropriate to turn a text bullet list (denoted by *) into + # an html equivalent. + # Can only handle a single bullet list. + my ($ra_contents, ) = @_; + my $found_list = 0; + foreach my $l (@{$ra_contents}) { + if ($l =~ /^\s*\*/) { + $found_list = 1; + last; + } + } + return unless $found_list; # bail if no list found + + # find the first and last lines of the bullet list + my $start_line = 0; + for (my $i = 0; $i < scalar @{$ra_contents}; $i++) { + if ($ra_contents->[$i] =~ /^\s*\*/) { + $start_line = $i; + last; + } + } + my $end_line = 0; + for (my $i = scalar @{$ra_contents} - 1; $i >= 0; $i--) { + if ($ra_contents->[$i] =~ /^\s*\*/) { + $end_line = $i; + last; + } + } + + # finally, insert the HTML + for (my $i = 0; $i < scalar @{$ra_contents}; $i++) { + $ra_contents->[$i] =~ s{^(\s*)\*}{$1 <li>}; + $ra_contents->[$i] = "<ul> " . $ra_contents->[$i] if $i == $start_line; + $ra_contents->[$i] = $ra_contents->[$i] . "</ul>" if $i == $end_line; + } +} # 1}}} + +# # # # # # # + +sub wanted { # populates global array @files + return unless -f and /^CONTENTS$/; + push @files, "$File::Find::dir/$_"; +}
new file mode 100755 --- /dev/null +++ b/src/admin/make_index @@ -0,0 +1,1148 @@ +#!/usr/bin/env perl +# +# Albert Danial Mar 21 2002 +# +# Creates .html files documenting all the functions in octave and +# octave-forge. + +use strict; +use File::Find; +use File::Basename; +use Text::Wrap; +use FileHandle; +use IPC::Open3; +use POSIX ":sys_wait_h"; + +## Local configuration; the OCTAVE directory should contain +# src/DOCSTRINGS (which is a build product) and scripts/. +my $OCTAVE = "../octave"; +my $tmpdir = "/tmp"; # temp directory +my $catdir = "index"; # output directory + +## Commands to grab the last few defs from octave +## Use the first def if you want to extract from +## a locally compiled version, or the second if you +## want to use the installed version. +#my $OCTAVECMD = "LD_LIBRARY_PATH=$OCTAVE/src/:$OCTAVE/liboctave:$OCTAVE/libcruft $OCTAVE/src/octave -q"; +#my $OCTAVEINIT = "path='.:$OCTAVE/src//:$OCTAVE/scripts//'; suppress_verbose_help_message = 1;"; +my $OCTAVECMD = "octave -q"; +my $OCTAVEINIT = "suppress_verbose_help_message = 1;"; + +# Links to octave/octave-forge web CVS +my $OCTAVECVS = "http://www.octave.org/cgi-bin/viewcvs.cgi/~checkout~/octave"; +my $FORGECVS = "http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/*checkout*/octave/octave-forge/"; + +#my $script = basename($0); + +my $forgebar = qq~<center> +<A href="http://octave.sourceforge.net">Home</A> | +<A href="http://sourceforge.net/projects/octave/">Summary</A> | +<A href="http://sourceforge.net/forum/?group_id=2888">Forums</A> | +<A href="http://sourceforge.net/bugs/?group_id=2888">Bugs</A> | +<A href="http://sourceforge.net/support/?group_id=2888">Support</A> | +<A href="http://sourceforge.net/patch/?group_id=2888">Patches</A> | +<A href="http://sourceforge.net/mail/?group_id=2888">Lists</A> | +<A href="http://sourceforge.net/pm/?group_id=2888">Tasks</A> | +<A href="http://sourceforge.net/docman/?group_id=2888">Docs</A> | +<A href="http://sourceforge.net/survey/?group_id=2888">Surveys</A> | +<A href="http://sourceforge.net/news/?group_id=2888">News</A> | +<A href="http://sourceforge.net/cvs/?group_id=2888">CVS</A> | +<A href="http://sourceforge.net/project/showfiles.php?group_id=2888">Files</A> +</center> + ~; + +my $forgelink = qq~ +<hr><center> +<small>Hosted by</small> <a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=2888&type=4" width="125" height="37" border="0" alt="SourceForge.net Logo" /></a> +</center> + ~; + +# initialize the indexing variables +my %index_by_TB_cat = (); # i_TB_cat{toolbox}{category} = list of functions +my %index_by_function = (); # i_function{function} =[ [toolbox_1,category_1], +# [toolbox_2,category_2],..] +my %TB_description = (); +my %index_notes = (); # index_notes{function} = comment + +# find and load all indices +my @index_files = (); +find(\&index_files, "."); +sub index_files { # {{{1 populates global array @files + return unless -f and /INDEX$/; # INDEX files + my $path = "$File::Find::dir/$_"; + $path =~ s|^[.]/||; + push @index_files, $path; +} # 1}}} +foreach my $f ( @index_files ) { + load_index($f, + \%index_by_TB_cat, + \%TB_description, + \%index_by_function); +} + +# XXX FIXME XXX should die if the index is empty +# die "No INDEX in current directory" if !-e "INDEX"; +my $summary = !-e "admin/make_index"; # if not in the root, just summarize +my $include_octave = !$summary; # only include octave if not summarizing + +# locate all C++ and m-files in octave-forge, and all m-files in octave +# don't need C++ files from octave because we have DOCSTRINGS +my @m_files = (); +my @C_files = (); +find(\&cc_and_m_files, "$OCTAVE/scripts") if $include_octave; +find(\&cc_and_m_files, "$OCTAVE/src") if $include_octave; + # or just use $OCTAVE/{src,scripts}/DOCSTRINGS .... +find(\&cc_and_m_files, "."); +sub cc_and_m_files { # {{{1 populates global array @files + return unless -f and /\.(m|cc|l|y)$/; # .m and .cc files (lex & yacc too!) + my $path = "$File::Find::dir/$_"; + $path =~ s|^[.]/||; + if (/\.m$/) { + push @m_files, $path; + } else { + push @C_files, $path; + } +} # 1}}} + +my %function_description = (); +my %octave_forge_function = (); +my @uncategorized = (); +my @skipped = (); +my %n_appearances = (); +my $n_functions = 0; +my @shadow_paths = ('FIXES', 'extra/NaN', 'extra/Windows', 'extra/ver20'); +my @shadowed = (); + +# grab help from C++ files +foreach my $f ( @C_files ) { + if ( open(IN,$f) ) { + while (<IN>) { + # skip to the next function + next unless /^\s*DEF(UN[ (]|UN_MAPPER|UN_DLD|CMD|VAR|CONST)/; + + # print "looking at $_"; + # extract function name to pattern space + /\((\w*)\s*,/; + # remember function name + my $function = $1; + # print " found function $function\n"; + + # skip to second , to skip default string options of DEFVAR + # comment if third or higher arg + # XXX FIXME XXX What about if the string arg includes , + # XXX FIXME XXX What if second , is not on first line!! + # Special cases + # * for DEFCONST (I, Complex (0., 1.), + s/\(\w*\s*,\s*Complex\s*\(\s*[0-9.]*\s*,\s*[0-9.]*\s*\),//; + # * for macro containing DEFUN_DLD + s/\w*\s*\(\w*\s*,\s*"/"/; + # Main case + s/\(\w*\s*,.*?,//; + + # If we have nothing but a newline, skip + $_ = <IN> if /^\s*DEF(UN[ (]|UN_MAPPER|UN_DLD|CMD|VAR|CONST)\s*,*\s*\n/; + + # if line contains \w+_DOC_STRING we have a macro for the + # help text + my $desc; + if (/\w+_DOC_STRING/) { + my $macro = $_; + $macro =~ s/^.*?\s*(\w*_DOC_STRING).*$/$1/; + $macro =~ s/\n//; + + my $line; + if ( open(IN2, $f) ) { + while ($line = <IN2>) { + next unless $line =~ /^\#\s*define\s+$macro\s+\"/; + $desc = $line; + $desc =~ s/^\#\s*define\s+$macro\s+\"(.*\n)$/$1/; + while ($desc !~ /[^\\]\"/ && $desc !~ /^\"/) { + $desc =~ s/\\\s*\n//; + # join with the next line + $desc .= <IN2>; + } + $desc = "" if $desc =~ /^\"/; # chop everything if it was "" + $desc =~ s/\\n/\n/g; # insert fake line ends + $desc =~ s/([^\"])\".*$/$1/; # chop everything after final '"' + $desc =~ s/\\\"/\"/; # convert \"; XXX FIXME XXX \\" + last; + } + close (IN2); + } else { + print STDERR "Could not open file ($f): $!\n"; + } + } else { + # skip to next line if comment doesn't start on this line + # XXX FIXME XXX maybe we want a loop here? + $_ = <IN> unless /\"/; + # skip to the beginning of the comment string by + # chopping everything up to opening " + $desc = $_; + $desc =~ s/^[^\"]*\"//; + + # join lines until you get the end of the comment string + # plus a bit more. You need the "plus a bit more" because + # C compilers allow implicitly concatenated string constants + # "A" "B" ==> "AB". + while ($desc !~ /[^\\]\"\s*[\,\)]/ && $desc !~ /^\"/) { + # if line ends in '\', chop it and the following '\n' + $desc =~ s/\\\s*\n//; + # join with the next line + $desc .= <IN>; + # eliminate consecutive quotes, being careful to ignore + # preceding slashes. XXX FIXME XXX what about \\" ? + $desc =~ s/([^\\])\"\s*\"/$1/; + } + $desc = "" if $desc =~ /^\"/; # chop everything if it was "" + + # Now check for text included in help messages as macros + # XXX FIXME XXX These macros are often compile dependent, so + # how to we get the correct version of the macro in this case + # without actually compiling the code??? + while ($desc =~ /[^\\]\"\s*\S+\s*[^\\]\"/) { + my $macro = $desc; + # Deal with issues of multiple macros... + # $macro =~ s/^.*[^\\]\"\s*(\S+?)\s*[^\\]\".*$/$1/; + ($macro) = ($macro =~ /[^\\]\"\s*(\S+?)\s*\".*$/); + $macro =~ s/\n//; + my $macro_defn; + my $line; + if ( open(IN2, $f) ) { + while ($line = <IN2>) { + next unless $line =~ /^\#\s*define\s+$macro\s+\"/; + $macro_defn = $line; + $macro_defn =~ s/^\#\s*define\s+$macro\s+\"(.*)\n$/$1/; + while ($macro_defn !~ /[^\\]\"/ && $macro_defn !~ /^\"/) { + $macro_defn =~ s/\\\s*\n//; + # join with the next line + $macro_defn .= <IN2>; + } + $macro_defn = "" if $macro_defn =~ /^\"/; # chop everything if it was "" + $macro_defn =~ s/\\n/\n/g; # insert fake line ends + $macro_defn =~ s/([^\"])\".*$/$1/; # chop everything after final '"' + $macro_defn =~ s/\\\"/\"/; # convert \"; XXX FIXME XXX \\" + last; + } + close (IN2); + } else { + print STDERR "Could not open file ($f): $!\n"; + } + $desc =~ s/\"\s*$macro\s*\"/$macro_defn/; + } + } + + $desc =~ s/\\n/\n/g; # insert fake line ends + $desc =~ s/([^\"])\".*$/$1/; # chop everything after final '"' + $desc =~ s/\\\"/\"/; # convert \"; XXX FIXME XXX \\" +# print " description: $desc"; + + # register the function with a brief description + register_function($function,$desc,$f,0); + } + close (IN); + } else { + print STDERR "Could not open file ($f): $!\n"; + } +} + +# grab help from m-files (octave-forge and octave) +foreach my $f ( @m_files ) { + my $desc = extract_description($f); + my $function = basename($f, ('.m')); + die "Null function?? [$f]\n" unless $function; + register_function($function,$desc,$f,0); +} + +# grab help from octave's DOCSTRINGS +if ( !$include_octave ) { + # skip DOCSTRINGS if just summary +} +else { + + if (open (IN,"$OCTAVE/src/DOCSTRINGS")) { + process_docstrings(); + } else { + print STDERR "could not open $OCTAVE/src/DOCSTRINGS !\n"; + } + if (open (IN,"$OCTAVE/scripts/DOCSTRINGS")) { + process_docstrings(); + } else { + print STDERR "could not open $OCTAVE/scripts/DOCSTRINGS !\n"; + } +} + +# Desperate last measure. Try help <func> within octave. Good for getting +# keyword and operator descriptions +print "Perl hacker: please make the following faster\n"; +# XXX FIXME XXX, we shouldn't respawn a new octave process each time !!! +foreach my $TB ( toolbox_list()) { + foreach my $cat ( cat_list($TB) ) { + foreach my $func ( cat_funcs($TB,$cat) ) { + if (! defined $function_description{$func}[1] && ! defined $index_notes{$func} ) { + open3(*Writer, *Reader, *Errer, $OCTAVECMD) or die "Could not run octave"; + print Writer $OCTAVEINIT; + print Writer "help $func; 1"; close(Writer); + my @lines = <Reader>; close(Reader); + my @err = <Errer>; close(Errer); + waitpid(-1,&WNOHANG); + + # Display errors, if any + if (@err) { + print "help $func\n>>> @err"; + } else { + my $body = join("",@lines); + if ($body =~ /help: `(.*)' not found/ || $body =~ /help: sorry,/) { + # do nothing + } else { + print "help $func\n"; + + my $start; + if ($body =~ /^\n\*\*\*/) { + # clipping assuming ops/keywords only + $start = index($body,"$func") + 1 + length($func); + } else { + # first lines till \n\n will be octave tell us the type + # of variable/funtion and where it is found + $start = index($body,"\n\n") + 2; + } + my $stop = index($body,"ans ="); + $body = substr($body,$start,$stop-$start); + register_function($func,$body,$OCTAVE,0); + } + } + } + } + } +} + +# print a summary table rather than generating the html +if ( $summary ) { + write_ascii("% "); +} +else { + write_html(); +} + + +if (@skipped) { + print "skipped ", scalar(@skipped), " functions "; + my $rs = $,; $, = "\n "; + print " ", sort(@skipped); $, = $rs; + print "\n"; +} + +print_missing(); + +if (@uncategorized) { + print scalar(@uncategorized), " uncategorized functions "; + print "(out of ", $n_functions, " total)"; + my $rs = $,; $, = "\n "; + print " ", sort(@uncategorized); $, = $rs; + print "\n"; +# print wrap("\t", "\t", join(" ", sort @uncategorized)), "\n"; +} + +if (@shadowed) { + print "unexpected shadowing of ", scalar(@shadowed), " Octave functions"; + my $rs = $,; $, = "\n "; + print " ", sort(@shadowed); $, = $rs; + print "\n"; +# print wrap("\t", "\t", join(" ", sort @shadowed)), "\n"; +} + +sub process_docstrings { + my $function = ""; + my $desc = ""; + while (<IN>) { + if (/^\037/) { + register_function($function,$desc,$OCTAVE,1) unless $function eq ""; + $function = $_; + $function =~ s/^\037//; + $function =~ s/\n$//; + $desc = ""; + } else { + $desc .= $_; + } + } + register_function($function,$desc,$OCTAVE,1) unless $function eq ""; + close(IN); +} + +sub first_sentence { # {{{1 +# grab the first real sentence from the function documentation + my ($desc) = @_; + my $retval = ''; + my $line; + my $next; + my @lines; + + my $trace = 0; + # $trace = 1 if $desc =~ /Levenberg/; + return "" unless defined $desc; + if ($desc =~ /^\s*-[*]- texinfo -[*]-/) { + + # help text contains texinfo. Strip the indicator and run it + # through makeinfo. (XXX FIXME XXX this needs to be a function) + $desc =~ s/^\s*-[*]- texinfo -[*]-\s*//; + my $cmd = "makeinfo --fill-column 1600 --no-warn --no-validate --no-headers --force --ifinfo"; + open3(*Writer, *Reader, *Errer, $cmd) or die "Could not run info"; + print Writer "\@macro seealso {args}\n\n\@noindent\nSee also: \\args\\.\n\@end macro\n"; + print Writer "$desc"; close(Writer); + @lines = <Reader>; close(Reader); + my @err = <Errer>; close(Errer); + waitpid(-1,&WNOHANG); + + # Display source and errors, if any + if (@err) { + my $n = 1; + foreach $line ( split(/\n/,$desc) ) { + printf "%2d: %s\n",$n++,$line; + } + print ">>> @err"; + } + + # Print trace showing formatted output +# print "<texinfo--------------------------------\n"; +# print @lines; +# print "--------------------------------texinfo>\n"; + + # Skip prototype and blank lines + while (1) { + return "" unless @lines; + $line = shift @lines; + next if $line =~ /^\s*-/; + next if $line =~ /^\s*$/; + last; + } + + } else { + +# print "<plain--------------------------------\n"; +# print $desc; +# print "--------------------------------plain>\n"; + + # Skip prototype and blank lines + @lines = split(/\n/,$desc); + while (1) { + return "" if ($#lines < 0); + $line = shift @lines; + next if $line =~ /^\s*[Uu][Ss][Aa][Gg][Ee]/; # skip " usage " + next if $line =~ /^\s*-/; # skip " -- blah" + + $line =~ s/^\s*\w+\s*://; # chop " blah : " + print "strip blah: $line\n" if $trace; + $line =~ s/^\s*[Ff]unction\s+//; # chop " function " + print "strip function $line\n" if $trace; + $line =~ s/^\s*\[.*\]\s*=\s*//; # chop " [a,b] = " + print "strip []= $line\n" if $trace; + $line =~ s/^\s*\w+\s*=\s*//; # chop " a = " + print "strip a= $line\n" if $trace; + $line =~ s/^\s*\w+\s*\([^\)]*\)\s*//; # chop " f(x) " + print "strip f(x) $line\n" if $trace; + $line =~ s/^\s*[;:]\s*//; # chop " ; " + print "strip ; $line\n" if $trace; + + $line =~ s/^\s*[[:upper:]][[:upper:]0-9_]+//; # chop " BLAH" + print "strip BLAH $line\n" if $trace; + $line =~ s/^\s*\w*\s*[-]+\s+//; # chop " blah --- " + print "strip blah --- $line\n" if $trace; + $line =~ s/^\s*\w+ *\t\s*//; # chop " blah <TAB> " + print "strip blah <TAB> $line\n" if $trace; + $line =~ s/^\s*\w+\s\s+//; # chop " blah " + print "strip blah <NL> $line\n" if $trace; + +# next if $line =~ /^\s*\[/; # skip [a,b] = f(x) +# next if $line =~ /^\s*\w+\s*(=|\()/; # skip a = f(x) OR f(x) + next if $line =~ /^\s*or\s*$/; # skip blah \n or \n blah + next if $line =~ /^\s*$/; # skip blank line + next if $line =~ /^\s?!\//; # skip # !/usr/bin/octave + # XXX FIXME XXX should be testing for unmatched () in proto + # before going to the next line! + last; + } + } + + # Try to make a complete sentence, including the '.' + if ( "$line " !~ /[^.][.]\s/ && $#lines >= 0) { + my $next = $lines[0]; + $line =~ s/\s*$//; # trim trailing blanks on last + $next =~ s/^\s*//; # trim leading blanks on next + $line .= " $next" if "$next " =~ /[^.][.]\s/; # ends the sentence + } + + # Tidy up the sentence. + chomp $line; # trim trailing newline, if there is one + $line =~ s/^\s*//; # trim leading blanks on line + $line =~ s/([^.][.])\s.*$/$1/; # trim everything after the sentence + print "Skipping:\n$desc---\n" if $line eq ""; + + # And return it. + return $line; + +} # 1}}} +sub shadow_path { # {{{1 +# shadow_path($f) returns true if $f is on a known Octave shadow path + my ($file) = @_; + $file =~ s|/[^/]*$||; + my @matches = grep(/^$file$/,@shadow_paths); +# print "looking for $file in @shadow_paths\n"; +# print "returns ",@matches,"\n"; + return scalar(@matches) > 0 || $file =~ /alternatives$/; + +} # 1}}} +sub register_function { # {{{1 +# register the function and its one-line description + my ($function, # in $index{toolbox}{category} = [functions] + $desc, # in $toolbox_desc{toolbox} = description + $file, + $replace_shadow, + ) = @_; + ++$n_appearances{$function}; + if ($n_appearances{$function} > 1) { + if ($replace_shadow != 0) { + push @shadowed, "$file:$function" if $file =~ /^$OCTAVE/ + and !shadow_path($function_description{$function}[0]); + # print "$file:$function appeared previously\n"; + } + } else { + ++$n_functions; + } + + $octave_forge_function{$function} = 1 unless $file =~ /^$OCTAVE/; + if (!defined $index_by_function{$function}) { + my $entry = $file; + $entry = "$file: $function" if $file !~ /[.]m$/; + if ($function =~ /__/ || $file =~ /test/ + || $function =~ /^[Cc]ontents?$/) { + push @skipped, $entry; + } else { + push @uncategorized, $entry; + } + } + + my $oneline = first_sentence($desc); + #printf "%30s %s\n", $function, $oneline; + if ($replace_shadow == 0 && defined @function_description{$function}) { + @function_description{$function} = [ $function_description{$function}[0], $oneline, $desc ]; + } elsif (!defined @function_description{$function}) { + @function_description{$function} = [ $file, $oneline, $desc ]; + } +# push @function_description{$function}}, "$file\n$oneline\n$desc"; + #printf "%-12s %-20s %s\n", $function, + # $index_by_function{$function}[0], + # $index_by_function{$function}[1]; +} # 1}}} +sub extract_description { # {{{1 +# grab the entire documentation comment from an m-file + my ($file) = @_; + my $retval = ''; + + if( open( IN, "$file")) { + # skip leading blank lines + while (<IN>) { + last if /\S/; + } + if( m/\s*[%\#][\s\#%]* Copyright/) { + # next block is copyright statement, skip it + while (<IN>) { + last unless /^\s*[%\#]/; + } + } + # Skip everything until the next comment block + while ( !/^\s*[\#%]/ ) { + $_ = <IN>; + last if not defined $_; + } + # Return the next comment block as the documentation + while (/^\s*[\#%]/) { + s/^[\s%\#]*//; # strip leading comment characters + s/[\cM\s]*$//; # strip trailing spaces. + $retval .= "$_\n"; + $_ = <IN>; + last if not defined $_; + } + close(IN); + return $retval; + } + else { + print STDERR "Could not open file ($file): $!\n"; + } +} # 1}}} +sub load_index { # {{{1 + my ($file) = @_; # in + my $toolbox = "extra"; + my $category = ""; + my $description = ""; + my $function = ""; + open(IN, $file) or die "Cannot read $file: $!\n"; + my %map; # simple macros for use in notes + while (<IN>) { + next if /^\s*$/; # skip blank lines + next if /^\s*\#/; # skip comment lines + chomp; + if (/^(.*?)\s*>>\s*(.*?)$/) { + # toolbox lines contain "word >> description" + $toolbox = $1; + $description = $2; + $category = ""; + $TB_description{$toolbox} = $description; + } elsif (/^\s*\$(\w+)\s*=\s*(\S.*\S)\s*$/) { + # define a variable as "$var = expansion" + $map{$1} = $2; + } elsif (/^(\w.*?)\s*$/) { + # category lines start in the left most column + $category = $1; + } elsif (/^\s+(\S.*[^=~!><])=\s*(\S.*\S)\s*$/) { + # Process "function = notes" explicit descriptions + $function = $1; + $description = $2; + + # We used ...(\S.*)=... rather than (\S.*\S)\s*= to allow for + # single character function names, but that means we may have + # to trim some extra spaces of the function name. Single + # character descriptions get the treatment they deserve. + $function =~ s/\s+$//; + + # expand all $var in the description + my @parts = split('\$', $description); + foreach my $i ( 1 .. $#parts ) { + $parts[$i] =~ /^(\w+)(\W.*)$/ or $parts[$i] =~ /^(\w+)()$/; + $parts[$i] = "$map{$1}$2"; + } + $description = join("",@parts); + + # record the function->description mapping + $index_notes{$function} = $description; + die "Function $function (line $.) has no category" unless $category; + push @{$index_by_TB_cat{$toolbox}{$category}}, $function; + push @{$index_by_function{$function}}, [$toolbox, $category]; + } else { + s/^\s+//; + my @list = split /\s+/; + while ($#list >= 0) { + $function = shift @list; + die "Function $function (line $.) has no category" unless $category; + push @{$index_by_TB_cat{$toolbox}{$category}}, $function; + push @{$index_by_function{$function}}, [$toolbox, $category]; + + } + } + } + close(IN); +} # 1}}} +sub write_html { # {{{1 + # make empty html directories + unlink <$catdir/*.html>; + unlink <$catdir/f/*.html>; + mkdir "$catdir"; + mkdir "$catdir/f"; + + write_main(); + write_forgebar(); + write_intro(); + write_alphabetic_navbar(); + write_TBnavbar(); + foreach ( toolbox_list() ) { + write_TBnavbar($_); + write_TBdetails($_); + } + + # Write one file for each letter. + # + + my $Letter = chr(0); + foreach my $func ( indexed_funcs() ) { + # The source file + + my $body = long_desc($func); + if ($body ne "") { + # XXX FIXME XXX this will die if the punctuation is too wild + open FUNC, ">$catdir/f/$func.html" or die "Could not open $func.html"; + print FUNC "<html><head><title>$func</title></head>\n"; + print FUNC "<body>\n"; + print FUNC "<table width=100%><tr><td align=left><b>$func</b>\n"; + # The toolboxes to which it belongs + foreach my $pair ( @{$index_by_function{$func}} ) { + my ( $TB, $cat ) = @{$pair}; + print FUNC " ", cat_ref_up($TB, $cat, "[$TB]"), "\n"; + } + print FUNC " <td align=right>", download_ref($func), "</table>\n"; + print FUNC "$body\n"; + print FUNC "$forgelink\n</body></html>"; + close FUNC; + } + + # Check if need to go to the next letter + # This is particularly complicated because we + # want to include all punctuation in the + my $next = uc(substr($func, 0, 1)); + if ($next ne $Letter) { + if ($Letter =~ /[A-Y]/) { + print OUT "</dl>\n$forgelink\n</body></html>\n"; + close OUT; + } else { + print OUT "</dl>\n"; + } + if ($Letter =~ /[\0A-Y]/) { + my $head = ""; + if ( $next =~ /[A-Z]/ ) { + $head = $next; + } elsif ( $next lt "A" ) { + $head = "A"; + } else { + $head = "Z"; + } + my $file = ">$catdir/$head.html"; + open(OUT, $file) or die "Cannot write $file"; + print OUT "<html><head>\n"; + print OUT "<title>Octave Functions: $head</title>\n"; + print OUT "<meta name=\"keywords\" content=\"\"></head>\n"; + print OUT "<body>\n"; + } + $Letter = $next; + print OUT "<h1><a name=\"$Letter\">$Letter</a></h1>"; + print OUT "<dl>\n"; + } + + # Function reference + print OUT "<dt><table width=100%><tr><td align=left><b>",func_ref($func,$func),"</b>\n"; + # The toolboxes to which it belongs + foreach my $pair ( @{$index_by_function{$func}} ) { + my ( $TB, $cat ) = @{$pair}; + print OUT " ", cat_ref($TB, $cat, "[$TB]"), "\n"; + } + print OUT " <td align=right>", download_ref($func), "</table>\n"; + + + # column 3: the function description + # XXX FIXME XXX multiple functions??? + print OUT " <dd>",html_desc($func),"\n"; + } + + print OUT "</dl>\n$forgelink\n</body></html>\n"; + close(OUT); +} # 1}}} +sub writenav { # 1{{{ + my ($cat) = @_; + +} # 1}}} +sub write_main { # {{{1 + open(OUT,">$catdir/index.html") or die "Could not open $catdir/index.html"; + print OUT <<EOF; +<HTML><HEAD> +<TITLE>Octave-forge combined index</TITLE> +</HEAD> +<FRAMESET rows="50, *"> + <FRAME src="forgebar.html" noresize frameborder="0"> + <FRAMESET cols="33%, 67%"> + <FRAME name=navbar src="categorical.html"> + <FRAMESET rows="50, *"> + <FRAME src="alphabetic.html"> + <FRAME name=content src="intro.html"> + </FRAMESET> + </FRAMESET> +<NOFRAMES> +$forgebar +<H1>Octave-Forge Combined Index</H1> +<ul> +<li><A HREF="categorical.html">Categorical index</a> +<li><A HREF="alphabetic.html">Alphabetic index</a> +</ul> +</NOFRAMES> +</FRAMESET> +</HTML> +EOF + close OUT; +} # 1}}} +sub write_forgebar { + open(OUT,">$catdir/forgebar.html") or die "Could not open index/forgebar.html"; + print OUT <<EOF; +<html><title>Octave Forge site navigator</title> +<base target=_top> +<body> +$forgebar +</body></html> +EOF +} +sub download_ref { +# download_ref($func,$desc) returns a link to download $func described by $desc + my ($func) = @_; + + my $path = $function_description{$func}[0]; + if ($path ne "" && $path !~ /^$OCTAVE/) { + return "[<a href=\"$FORGECVS$path\?rev=HEAD\&content-type=text/plain\">octave-forge/$path</a>]"; + } elsif ($path =~ /^$OCTAVE/) { + $path =~ s/^$OCTAVE//; + return "[<a href=\"$OCTAVECVS$path\?rev=HEAD\&content-type=text/plain\">octave$path</a>]"; + } else { + return ""; + } +} +sub write_intro { # 1{{{ + open(OUT,">$catdir/intro.html") or die "Could not open $catdir/intro.html"; + print OUT <<EOF; +<HTML><HEAD><TITLE>Octave-forge index intro</TITLE></HEAD> +<BODY> +<H1>Welcome to Octave-forge</H1> +$forgelink +</BODY></HTML> +EOF + close OUT; +} # 1}}} +sub write_TBnavbar { # 1{{{ + my $openTB = shift; + my $file = "categorical"; + $file = "nav$openTB" if $openTB ne ""; + open(OUT,">$catdir/$file.html") or die "Could not open $catdir/$file.html"; + print OUT <<EOF; +<html><head><title>Octave-forge categorical index</title></head> +<body> +What\'s available: +<ol> +EOF + foreach my $TB (toolbox_list()) { +# print OUT "<li><a href=\"$TB.html\" target=content><a href=\"nav$TB.html#$TB\" target=navbar>$TB_description{$TB}</a></a>"; + print OUT "<li>"; + if ($openTB eq $TB) { + print OUT "<a name=\"$TB\"><a href=\"categorical.html#$TB\" target=navbar> +$TB_description{$TB}</a></a>"; + print OUT "<ul>\n"; + foreach my $cat ( cat_list($TB) ) { + my $anchor = cat_anchor($cat); + print OUT " <li><a href=\"$TB.html#$anchor\" target=content>$cat</a></li>\n"; + } + print OUT "</ul>\n"; + } else { + print OUT "<a name=\"$TB\"><a href=\"nav$TB.html#$TB\" target=navbar>$TB_description{$TB}</a></a>"; + } + } + print OUT "</ol>\n</body></html>"; + close OUT; +} # 1}}} +sub write_TBdetails { # 1{{{ + my $TB = shift; + my $file = "$catdir/$TB.html"; + + open(OUT, ">$file") or die "Cannot write $file: $!\n"; + print OUT <<EOF; +<html><head> +<title>$TB</title> +<meta name=\"keywords\" content=\"\"> +</head> +<body> +<h1>$TB_description{$TB}</h1> +EOF + + # summary list of categories + print OUT "<ul>\n"; + foreach my $cat ( cat_list($TB) ) { + my $anchor = cat_anchor($cat); + print OUT " <li><a href=\"#$anchor\">$cat</a></li>\n"; + } + print OUT "</ul>\n"; + + # Each category has a table of its functions and their descriptions. + foreach my $cat ( cat_list($TB) ) { + my $anchor = cat_anchor($cat); + print OUT "<h2><a name=\"$anchor\">$cat</a></h2>\n"; + print OUT "<dl>\n"; + foreach my $func ( cat_funcs($TB,$cat) ) { + + # column 1: the function (x-ref to full description in + # cvs-tree's html file) + print OUT "<dt><table width=100%><tr><td align=left><b>",func_ref($func,$func),"</b>\n"; + print OUT " <td align=right>", download_ref($func), "</table>\n"; + + # column 2: the description, if it exists + # + print OUT "<dd>",html_desc($func),"\n"; + } + print OUT "</dl>\n"; + } + print OUT "$forgelink\n</body></html>\n"; + close(OUT); +} # 1}}} +sub write_alphabetic_navbar { # 1{{{ + open(OUT,">$catdir/alphabetic.html") or die "Could not open $catdir/alphabetic.html"; + print OUT <<EOF; +<html><head><title>Octave-Forge alphabetic list</title></head> +<base target=content> +<body> +EOF + my $A_to_Z = ""; + foreach (first_letters (indexed_funcs())) { + $A_to_Z .= letter_ref($_) . "|"; + } + $A_to_Z =~ s/\s*\|\s*$//; # strip last pipe separator + print OUT "<center>$A_to_Z</center>\n</body></html>\n"; + close OUT; +} # 1}}} +sub oldnavbar { # 1{{{ + my $max_TB_across_top = 7; + my $all_toolboxes = "<center>\n"; + my $n = 0; + + foreach my $TB (toolbox_list()) { + ++$n; + if ($n > $max_TB_across_top) { + $n = 0; + $all_toolboxes .= "<a href=\"$TB.html\">$TB</a> <br> "; + } else { + $all_toolboxes .= "<a href=\"$TB.html\">$TB</a> | "; + } + } + $all_toolboxes =~ s/\s+\|\s*$//; # strip last pipe separator + $all_toolboxes .= "<br><br>"; + my $A_to_Z = ""; + foreach (first_letters (indexed_funcs())) { + $A_to_Z .= letter_ref($_); + $A_to_Z .= " | "; + } + $A_to_Z =~ s/\s+\|\s*$//; # strip last pipe separator + my $all_toolboxes_A_Z = $all_toolboxes . "$A_to_Z </center>\n"; + $all_toolboxes .= "</center>\n"; + +} # 1}}} +sub print_missing { + my $printmissing = 1; + foreach my $TB ( toolbox_list() ) { + my $printTB = 1; + foreach my $cat ( cat_list($TB) ) { + my $printcat = 1; + foreach my $func ( cat_funcs($TB,$cat) ) { + if (! defined $function_description{$func}[1] && ! defined $index_notes{$func} ) { + print "missing functions:" if $printmissing; + print "\n [$TB]" if $printTB; + print "\n $cat\n >" if $printcat; + print " $func"; + $printTB = 0; + $printcat = 0; + $printmissing = 0; + } + } + } + } + print "\n" unless $printmissing; +} +sub write_ascii { # 1{{{ +# output all toolboxes as a contents.m file + my ($prefix) = @_; + my $indent = 16 - 3 - length($prefix); + + # XXX FIXME XXX add an option to spit out contents.m + # XXX FIXME XXX what if there is no toolbox? + # XXX FIXME XXX preserve category order + foreach my $TB ( toolbox_list() ) { + print wrap($prefix,$prefix,$TB_description{$TB}),"\n$prefix\n"; + foreach my $cat ( cat_list($TB) ) { + print wrap($prefix,$prefix,$cat), "\n"; + foreach my $func ( cat_funcs($TB,$cat) ) { + my $entry = sprintf("%-*s %s",$indent,$func,ascii_desc($func)); + print wrap("$prefix","$prefix\t\t"," $entry"), "\n"; + } + print "$prefix\n"; + } + } +} # 1}}} +sub cat_ref { # 1{{{ +# cat_ref($TB,$cat,$ref) returns an html link to $cat described by $ref + my ($TB,$cat,$ref) = @_; + my $anchor = cat_anchor($cat); + return "<a href=\"$TB.html#$anchor\">$ref</a>"; +} # 1}}} +sub cat_ref_up { # 1{{{ +# cat_ref($TB,$cat,$ref) returns an html link to $cat described by $ref + my ($TB,$cat,$ref) = @_; + my $anchor = cat_anchor($cat); + return "<a href=\"../$TB.html#$anchor\">$ref</a>"; +} # 1}}} +sub cat_anchor { # 1{{{ +# cat_anchor($cat) returns the anchor word generated for category $cat + my ($cat) = @_; + $cat =~ s/\W+//g; + return $cat; +} # 1}}} +sub func_ref { # 1{{{ +# func_ref($func) returns an html link to $func described by $ref + my ($func,$ref) = @_; + if ( defined $function_description{$func}[2] && + $function_description{$func}[2] ne "") { + return "<a href=\"f/$func.html\">$ref</a>"; + } elsif ( $ref ne $func ) { + # XXX FIXME XXX do we want "$ref ($func)"? Check how it is called. + return $ref; + } else { + return $ref; + } +} # 1}}} +sub split_long_name { # 1{{{ +# html magic to break long variable/function names + # XXX FIXME XXX this function is probably not used + my ( $nicefunc ) = @_; + # $nicefunc =~ s/([^_])_([^_])/$1_ $2/g; + return $nicefunc; +} # 1}}} +sub first_letters { # 1{{{ +# return a list of all first letters in the arguments +# The argument list must come sorted with a case-insensitive sort. + my $Letter = chr(0); + my @ret = (); + foreach my $name ( @_ ) { + # Check if need to go to the next letter + if (uc(substr($name, 0, 1)) ne $Letter) { + $Letter = uc(substr($name, 0, 1)); + push @ret, $Letter; + } + } + return @ret; +} # 1}}} +sub letter_file { # 1{{{ + return "$_.html" if /[A-Z]/; + return "A.html" if $_ lt "A"; + return "Z.html"; +} # 1}}} +sub letter_ref { # 1{{{ +# letter_ref($letter) returns a link to the letter + return "<a href=\"" . letter_file($_) . "#$_\">$_</a>"; +} # 1}}} +sub ascii_desc { # 1{{{ +# ascii_desc($func) returns a decription of $func using ascii markup + my ( $func ) = @_; + if (! defined $function_description{$func}[1] ) { + my $notes = $index_notes{$func}; + $notes = "<missing>" if $notes eq ""; + # convert "<a link>desc</a>" to "desc (link)" + $notes =~ s|<a href=\"?([^>]*)\"?>([^<]*)</a>|$2 ($1)|g; + # strip all remaining html formatting + $notes =~ s|<[^>]*>||g; + return $notes; + } else { + my $desc = $function_description{$func}[1]; + if ($desc eq "") { + return "<no description>"; + } else { + return $desc; + } + } +} #}}} +sub html_desc { # 1{{{ +# html_desc($func) returns a description of $func using html markup + my ( $func ) = @_; + my $notes = $index_notes{$func}; + if (! defined $function_description{$func}[1] ) { + $notes = "not implemented" if $notes eq ""; + # shut of the bold italics during "code" formatting + $notes =~ s|<code>|</i><code>|g; + $notes =~ s|</code>|</code><i>|g; + $notes =~ s|<f>(\w+)</f>|</i><code><a href="f/$1.html">$1</a></code><i>|g; + return "<i>$notes</i>"; + } else { + print "ignoring $func = $notes\n" if $notes ne ""; + my $desc = $function_description{$func}[1]; + if ($desc eq "") { + return "<i>no description</i>"; + } else { + return $desc; + } + } +} # 1}}} +sub long_desc { + my ( $func ) = @_; + my $body = $function_description{$func}[2]; + if ($body =~ /^\s*-[*]- texinfo -[*]-/) { + $body = info2html($func, $body); + } elsif ($body ne "") { + $body = "<pre>$body</pre>"; + } + return $body +} # 1}}} +sub info2html_texi2html { # 1{{{ +# run body through texi2html to produce html + my ( $func, $body ) = @_; + $body =~ s/^\s*-[*]- texinfo -[*]-//; + open(SRC, ">$func.texi"); + print SRC "\@macro seealso {args}\n\n\@noindent\nSee also: \\args\\.\n\@end macro\n"; + print SRC "BEGINCUT $body ENDCUT"; + close SRC; + system ("texi2html -expand info $tmpdir/$func.texi"); + open(SRC, "<$func.html"); + my @lines = <SRC>; + close SRC; + $body = join("",@lines); + my $start = index($body,"BEGINCUT") + 8; + my $stop = index($body,"ENDCUT"); + $body = substr($body,$start,$stop-$start); + unlink "$func.texi", "$func.html"; +} # 1}}} +sub info2html { # 1{{{ +# run body through makeinfo to produce html + my ( $func, $body ) = @_; + $body =~ s/^\s*-[*]- texinfo -[*]-//; + my $cmd = "makeinfo --fill-column 80 --no-warn --no-validate --force --html --ifinfo -o -"; + open3(*Writer, *Reader, *Errer, $cmd) or die "Could not run info"; + print Writer "\@macro seealso {args}\n\n\@noindent\nSee also: \\args\\.\n\@end macro\n"; + # I have no idea why but makeinfo is introducing some weirdness with <p> + # at the front of the document. The following works for my particular + # version but I have little hope for it working in general + print Writer "-CUT HERE $body"; close(Writer); + my @lines = <Reader>; close(Reader); + my @err = <Errer>; close(Errer); + waitpid(-1,&WNOHANG); + # strip everything before <body> and after </body> + $body = join("",@lines); + my $start = index($body,"CUT HERE") + 8; + my $stop = index($body,"</body"); + $body = substr($body,$start,$stop-$start); + $body =~ s|\@var\{([^\}]*)\}|<var>$1</var>|g; + return $body; +} # 1}}} +sub toolbox_list { # 1{{{ +# toolbox_list() returns an ordered list of toolboxes. + return sort { uc($a) cmp uc($b) } keys %index_by_TB_cat; +} # 1}}} +sub cat_list { # 1{{{ +# cat_list($TB) returns an ordered list of categories in a toolbox $TB. + my ($TB) = @_; + return sort keys %{$index_by_TB_cat{$TB}}; +} # 1}}} +sub cat_funcs { # 1{{{ +# cat_funcs($TB,$cat) returns an ordered list of functions in $TB,$cat + my ($TB,$cat) = @_; + return sort { uc($a) cmp uc($b) } @{$index_by_TB_cat{$TB}{$cat}} +} # 1}}} +sub indexed_funcs { # 1{{{ +# indexed_funcs() returns an ordered list of all functions in the index + return sort { uc($a) cmp uc($b) } keys %index_by_function; +} # 1}}} +sub forge_funcs { # 1{{{ +# forge_funcs() returns an ordered list of functions only found in octave forge + return sort { uc($a) cmp uc($b) } keys %octave_forge_function; +} # 1}}} +sub scanned_funcs { # 1{{{ +# scanned_funcs() returns an ordered list of all functions found in m-files and oct-files + return sort { uc($a) cmp uc($b) } %function_description; +} # 1}}} +__END__ +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +This program is granted to the public domain. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE.
new file mode 100755 --- /dev/null +++ b/src/admin/mkdoc @@ -0,0 +1,137 @@ +#!/usr/bin/env perl +# +# David Bateman Feb 02 2003 +# +# Extracts the help in texinfo format from *.cc and *.m files for use +# in documentation. Based on make_index script from octave_forge. + +use strict; +use File::Find; +use File::Basename; +use FileHandle; + +my $docdir = "."; +if (@ARGV) { + $docdir = @ARGV[0]; +} + +# locate all C++ and m-files in current directory +my @m_files = (); +my @C_files = (); +find(\&cc_and_m_files, $docdir); + +sub cc_and_m_files { # {{{1 populates global array @files + return unless -f and /\.(m|cc)$/; # .m and .cc files + my $path = "$File::Find::dir/$_"; + $path =~ s|^[.]/||; + if (/\.m$/) { + push @m_files, $path; + } else { + push @C_files, $path; + } +} # 1}}} + +# grab help from C++ files +foreach my $f ( @C_files ) { + # XXX FIXME XXX. Should run the preprocessor over the file first, since + # the help might include defines that are compile dependent. + if ( open(IN,$f) ) { + while (<IN>) { + # skip to the next function + next unless /^DEFUN_DLD/; + + # extract function name to pattern space + /\((\w*)\s*,/; + # remember function name + my $function = $1; + # skip to next line if comment doesn't start on this line + # XXX FIXME XXX maybe we want a loop here? + $_ = <IN> unless /\"/; + # skip to the beginning of the comment string by + # chopping everything up to opening " + my $desc = $_; + $desc =~ s/^[^\"]*\"//; + # join lines until you get the end of the comment string + # plus a bit more. You need the "plus a bit more" because + # C compilers allow implicitly concatenated string constants + # "A" "B" ==> "AB". + while ($desc !~ /[^\\]\"\s*\S/ && $desc !~ /^\"/) { + # if line ends in '\', chop it and the following '\n' + $desc =~ s/\\\s*\n//; + # join with the next line + $desc .= <IN>; + # eliminate consecutive quotes, being careful to ignore + # preceding slashes. XXX FIXME XXX what about \\" ? + $desc =~ s/([^\\])\"\s*\"/$1/; + } + $desc = "" if $desc =~ /^\"/; # chop everything if it was "" + $desc =~ s/\\n/\n/g; # insert fake line ends + $desc =~ s/([^\"])\".*$/$1/; # chop everything after final '"' + $desc =~ s/\\\"/\"/; # convert \"; XXX FIXME XXX \\" + $desc =~ s/$//g; # chop trailing ... + + if (!($desc =~ /^\s*-[*]- texinfo -[*]-/)) { + my $err = sprintf("Function %s, does not contain texinfo help\n", + $function); + print STDERR "$err"; + } + my $entry = sprintf("\037%s\n%s", $function, $desc); + print "$entry", "\n"; + } + close (IN); + } else { + print STDERR "Could not open file ($f): $!\n"; + } +} + +# grab help from m-files +foreach my $f ( @m_files ) { + my $desc = extract_description($f); + my $function = basename($f, ('.m')); + die "Null function?? [$f]\n" unless $function; + if (!($desc =~ /^\s*-[*]- texinfo -[*]-/)) { + my $err = sprintf("Function %s, does not contain texinfo help\n", + $function); + print STDERR "$err"; + } + my $entry = sprintf("\037%s\n%s", $function, $desc); + print "$entry", "\n"; +} + +sub extract_description { # {{{1 +# grab the entire documentation comment from an m-file + my ($file) = @_; + my $retval = ''; + + if( open( IN, "$file")) { + # skip leading blank lines + while (<IN>) { + last if /\S/; + } + if( m/\s*[%\#][\s\#%]* Copyright/) { + # next block is copyright statement, skip it + while (<IN>) { + last unless /^\s*[%\#]/; + } + } + # Skip everything until the next comment block + while ( !/^\s*[\#%]/ ) { + $_ = <IN>; + last if not defined $_; + } + # Return the next comment block as the documentation + while (/^\s*[\#%]/) { + s/^[\s%\#]*//; # strip leading comment characters + s/[\cM\s]*$//; # strip trailing spaces. + s/[\.*]$//; + $retval .= "$_\n"; + $_ = <IN>; + last if not defined $_; + } + close(IN); + return $retval; + } + else { + print STDERR "Could not open file ($file): $!\n"; + } +} # 1}}}
new file mode 100755 --- /dev/null +++ b/src/admin/mkpkgadd @@ -0,0 +1,27 @@ +#! /bin/sh + +if test $# -eq 1; then + dir="$1" +else + echo "usage: mkpkgadd directory" 1>&2 + exit 1 +fi + +cd $dir + +m_files=`echo *.m` +cxx_files=`echo *.cc` +ln_files=`echo *.octlink` + +if test "$m_files" != "*.m"; then + sed -n 's/^[#%][#%]* *PKG_ADD: *//p' $m_files +fi + +if test "$cxx_files" != "*.cc"; then + sed -n -e 's,^//* *PKG_ADD: *,,p' \ + -e 's,^/\** *PKG_ADD: *\(.*\) \*/$,\1,p' $cxx_files +fi + +if test "$ln_files" != "*.octlink" ; then + cat $ln_files +fi
new file mode 100755 --- /dev/null +++ b/src/admin/mktests.sh @@ -0,0 +1,73 @@ +#! /bin/sh + +# Where to find mkpkgadd +MKPKGADD=$1 + +# Create a new fntests.m file +echo "fid=fopen('fntests.log','wt');" > fntests.m +echo "if fid<0,error('could not open fntests.log for writing');end" >>fntests.m +echo "test('','explain',fid);" >> fntests.m +echo "passes=0; tests=0;" >>fntests.m + +# Find all toplevel non-cvs directories +DIRS="`find FIXES main/* extra/* nonfree/* -type d ! -name CVS -prune`" + +# Find the tests in that directory +for dir in $DIRS; do + dir=`echo $dir | sed -e "s-^\./--" ` + + # skip the NOINSTALL directories + if test -f "$dir/NOINSTALL"; then continue; fi + + # Create local copy of PKG_ADD for in place testing + if test -e "$dir/PKG_ADD" ; then rm -f $dir/PKG_ADD; fi + $MKPKGADD $dir > $dir/PKG_ADD + if test -z "`cat $dir/PKG_ADD`" ; then rm -f $dir/PKG_ADD; fi + + # Build a list of possible test files + FILES="" + + # Find all successfully compiled .cc files + cxx_files=`echo $dir/*.cc` + if test "$cxx_files" != "$dir/*.cc"; then + for file in $cxx_files; do + obj=`echo "$file" | sed -e 's-\.cc$-.o-'` + if test -f "$obj" ; then FILES="$FILES $file"; fi + done + fi + + # Find all m-files + m_files=`echo $dir/*.m` + if test "$m_files" != "$dir/*.m"; then FILES="$FILES $m_files"; fi + + # No C++ of m-files, so no testing + if test -z "$FILES" ; then continue; fi + + # Find all files with %!test or %!assert in them + # XXX FIXME XXX is there a system independent way of doing (test|assert) + TESTS=`grep -l -E '^%![ta][es]s' $FILES` + + NUMFILES=`echo $FILES | wc -w` + NUMTESTS=`echo $TESTS | wc -w` + prompt="$dir [tests $NUMTESTS of $NUMFILES files]" + + # if no files have tests in them, skip + echo "printf('%s','$prompt'); disp('');" >>fntests.m + if test -z "$TESTS" ; then + echo "printf('%-40s ---> success','');disp('');" >>fntests.m + else + echo "dp=dn=0;" >>fntests.m + for file in $TESTS ; do + echo "[p,n] = test('$file','quiet',fid);" >>fntests.m + echo "dp += p; dn += n;" >>fntests.m + done + echo "if dp==dn, printf('%-40s ---> success',''); else" >>fntests.m + echo "printf('%-40s ---> passes %d out of %d tests','',dp,dn); end" >>fntests.m + echo "disp(''); passes += dp; tests += dn;" >>fntests.m + fi + +done + +echo "printf('passes %d out of %d tests',passes,tests);disp('');" >> fntests.m +echo "printf('see fntests.log for details');disp('');" >> fntests.m +echo "fclose(fid);" >> fntests.m
new file mode 100755 --- /dev/null +++ b/src/admin/mktexi @@ -0,0 +1,433 @@ +#!/usr/bin/env perl +# +# David Bateman Feb 02 2003 +# +# Extracts the help in texinfo format for particular function for use +# in documentation. Based on make_index script from octave_forge. + +use strict; +use File::Find; +use File::Basename; +use Text::Wrap; +use FileHandle; +use IPC::Open3; +use POSIX ":sys_wait_h"; + +my $file = shift @ARGV; +my $docfile = shift @ARGV; +my $indexfile = shift @ARGV; +my $line; + +if ( open(IN,$file) ) { + $line = <IN>; + my $tex = 0; + while ($line) { + if ($line =~ /^\@DOCSTRING/) { + my $found = 0; + my $func = $line; + $func =~ s/\@DOCSTRING\(//; + $func =~ s/\)[\n\r]+//; + my $func0 = $func; + my $func1 = $func; + $func0 =~ s/,.*$//; + $func1 =~ s/^.*,//; + if ( open(DOC,$docfile) ) { + while (<DOC>) { + next unless /\037/; + my $function = $_; + $function =~ s/\037//; + $function =~ s/[\n\r]+//; + if ($function =~ /^$func0$/) { + my $desc = ""; + my $docline; + my $doctex = 0; + while (($docline = <DOC>) && ($docline !~ /^\037/)) { + $docline =~ s/^\s*-[*]- texinfo -[*]-\s*//; + if ($docline =~ /\@tex/) { + $doctex = 1; + } + if ($doctex) { + $docline =~ s/\\\\/\\/g; + } + if ($docline =~ /\@end tex/) { + $doctex = 0; + } + $desc .= $docline; + } + $desc =~ s/$func0/$func1/g; + $desc =~ s/\@seealso\{(.*[^}])\}/See also: \1/g; + print "$desc", "\n"; + $found = 1; + last; + } + } + close (DOC); + if (! $found) { + print "\@emph{Not implemented}\n"; + } + } else { + print STDERR "Could not open file $docfile\n"; + exit 1; + } + } elsif ($line =~ /^\@REFERENCE_SECTION/) { + my $secfound = 0; + my $sec = $line; + $sec =~ s/\@REFERENCE_SECTION\(//; + $sec =~ s/\)[\n\r]+//; + my @listfunc = (); + my $nfunc = 0; + my $seccat = 0; + + if ( open(IND,$indexfile) ) { + while (<IND>) { + next unless /^[^ ]/; + my $section = $_; + $section =~ s/[\n\r]+//; + if ($section =~ /^(.*?)\s*>>\s*(.*?)$/) { + $section =~ s/.*>>(.*)/\1/; + $seccat = 1; + } + $section =~ s/^ *//; + $section =~ s/ *$//; + if ($section =~ /^$sec$/) { + if ($seccat) { + print "\@iftex\n"; + print "\@section Functions by Category\n"; + # Get the list of categories to index + my $firstcat = 1; + my $category; + while (<IND>) { + last if />>/; + if (/^[^ ]/) { + if (! $firstcat) { + print "\@end table\n"; + } else { + $firstcat = 0; + } + $category = $_; + $category =~ s/[\n\r]+//; + print "\@subsection $category\n"; + print "\@table \@asis\n"; + } elsif (/^\s+(\S.*\S)\s*=\s*(\S.*\S)\s*$/) { + my $func = $1; + my $desc = $2; + print "\@item $func\n"; + print "$desc\n"; + print "\n"; + } else { + if ($firstcat) { + print STDERR "Error parsing index file\n"; + exit 1; + } + s/^\s+//; + my @funcs = split /\s+/; + while ($#funcs >= 0) { + my $func = shift @funcs; + $func =~ s/^ *//; + $func =~ s/[\n\r]+//; + push @listfunc, $func; + $nfunc = $nfunc + 1; + print "\@item $func\n"; + print func_summary($func, $docfile); + print "\n"; + } + } + } + if (! $firstcat) { + print "\@end table\n"; + } + print "\n\@section Functions Alphabetically\n"; + print "\@end iftex\n\n"; + } else { + # Get the list of functions to index + my $indline; + while (($indline = <IND>) && ($indline =~ /^ /)) { + if ($indline =~ /^\s+(\S.*\S)\s*=\s*(\S.*\S)\s*$/) { + next; + } + $indline =~ s/^\s+//; + my @funcs = split(/\s+/,$indline); + while ($#funcs >= 0) { + my $func = shift @funcs; + $func =~ s/^ *//; + $func =~ s/[\n\r]+//; + push @listfunc, $func; + $nfunc = $nfunc + 1; + } + } + } + $secfound = 1; + last; + } + } + close (IND); + if (! $secfound) { + print STDERR "Did not find section $sec\n"; + } + } else { + print STDERR "Could not open file $indexfile\n"; + exit 1; + } + + @listfunc = sort(@listfunc); + my @listfunc2 = (); + my $indent = 16 - 3; + print "\@menu\n"; + foreach my $func (@listfunc) { + if ( open(DOC,$docfile) ) { + my $found = 0; + while (<DOC>) { + next unless /\037/; + my $function = $_; + $function =~ s/\037//; + $function =~ s/[\n\r]+//; + if ($function =~ /^$func$/) { + $found = 1; + last; + } + } + close (DOC); + if ($found) { + push @listfunc2, $func; + my $func0 = "${func}::"; + my $entry = sprintf("* %-*s %s",$indent,$func0,func_summary($func,$docfile)); + print wrap("","\t\t","$entry"), "\n"; + } + } else { + print STDERR "Could not open file $indexfile\n"; + exit 1; + } + } + print "\@end menu\n"; + + my $up = "Function Reference"; + my $next; + my $prev; + my $mfunc = 1; + foreach my $func (@listfunc2) { + if ($mfunc == $nfunc) { + $next = ""; + } else { + $next = @listfunc2[$mfunc]; + $mfunc = $mfunc + 1; + } + print "\n\@node $func, $next, $prev, $up\n"; + if ($seccat) { + print "\@subsection $func\n\n"; + } else { + print "\@section $func\n\n"; + } + $prev = $func; + my $found = 0; + my $desc = ""; + if ( open(DOC,$docfile) ) { + while (<DOC>) { + next unless /\037/; + my $function = $_; + $function =~ s/\037//; + $function =~ s/[\n\r]+//; + if ($function =~ /^$func$/) { + my $docline; + my $doctex = 0; + while (($docline = <DOC>) && ($docline !~ /^\037/)) { + $docline =~ s/^\s*-[*]- texinfo -[*]-\s*//; + if ($docline =~ /\@tex/) { + $doctex = 1; + } + if ($doctex) { + $docline =~ s/\\\\/\\/g; + } + if ($docline =~ /\@end tex/) { + $doctex = 0; + } + $desc .= $docline; + } + $desc =~ s/\@seealso\{(.*[^}])\}/See also: \1/g; + print "$desc", "\n"; + $found = 1; + last; + } + } + close (DOC); + if (! $found) { + print "\@emph{Not implemented}\n"; + } + } else { + print STDERR "Could not open file $docfile\n"; + exit 1; + } + } + } else { + if ($line =~ /\@tex/) { + $tex = 1; + } + if ($tex) { + $line =~ s/\\\\/\\/g; + } + print "$line"; + if ($line =~ /\@end tex/) { + $tex = 0; + } + } + $line = <IN>; + } +} else { + print STDERR "Could not open file $file\n"; + exit 1; +} + +sub func_summary { # {{{1 + my ($func, # in function name + $docfile # in DOCSTRINGS + ) = @_; + + my $desc = ""; + my $found = 0; + if ( open(DOC,$docfile) ) { + while (<DOC>) { + next unless /\037/; + my $function = $_; + $function =~ s/\037//; + $function =~ s/[\n\r]+//; + if ($function =~ /^$func$/) { + my $docline; + my $doctex = 0; + while (($docline = <DOC>) && ($docline !~ /^\037/)) { + if ($docline =~ /\@tex/) { + $doctex = 1; + } + if ($doctex) { + $docline =~ s/\\\\/\\/g; + } + if ($docline =~ /\@end tex/) { + $doctex = 0; + } + $desc .= $docline; + } + $desc =~ s/\@seealso\{(.*[^}])\}/See also: \1/g; + $found = 1; + last; + } + } + close (DOC); + if (! $found) { + $desc = "\@emph{Not implemented}"; + } + } else { + print STDERR "Could not open file $docfile\n"; + exit 1; + } + return first_sentence($desc); +} # 1}}} + + +sub first_sentence { # {{{1 +# grab the first real sentence from the function documentation + my ($desc) = @_; + my $retval = ''; + my $line; + my $next; + my @lines; + + my $trace = 0; + # $trace = 1 if $desc =~ /Levenberg/; + return "" unless defined $desc; + if ($desc =~ /^\s*-[*]- texinfo -[*]-/) { + # help text contains texinfo. Strip the indicator and run it + # through makeinfo. (XXX FIXME XXX this needs to be a function) + $desc =~ s/^\s*-[*]- texinfo -[*]-\s*//; + my $cmd = "makeinfo --fill-column 1600 --no-warn --no-validate --no-headers --force --ifinfo"; + open3(*Writer, *Reader, *Errer, $cmd) or die "Could not run info"; + print Writer "\@macro seealso {args}\n\n\@noindent\nSee also: \\args\\.\n\@end macro\n"; + print Writer "$desc"; close(Writer); + @lines = <Reader>; close(Reader); + my @err = <Errer>; close(Errer); + waitpid(-1,&WNOHANG); + + # Display source and errors, if any + if (@err) { + my $n = 1; + foreach $line ( split(/\n/,$desc) ) { + printf "%2d: %s\n",$n++,$line; + } + print ">>> @err"; + } + + # Print trace showing formatted output +# print "<texinfo--------------------------------\n"; +# print @lines; +# print "--------------------------------texinfo>\n"; + + # Skip prototype and blank lines + while (1) { + return "" unless @lines; + $line = shift @lines; + next if $line =~ /^\s*-/; + next if $line =~ /^\s*$/; + last; + } + + } else { + +# print "<plain--------------------------------\n"; +# print $desc; +# print "--------------------------------plain>\n"; + + # Skip prototype and blank lines + @lines = split(/\n/,$desc); + while (1) { + return "" if ($#lines < 0); + $line = shift @lines; + next if $line =~ /^\s*[Uu][Ss][Aa][Gg][Ee]/; # skip " usage " + + $line =~ s/^\s*\w+\s*://; # chop " blah : " + print "strip blah: $line\n" if $trace; + $line =~ s/^\s*[Ff]unction\s+//; # chop " function " + print "strip function $line\n" if $trace; + $line =~ s/^\s*\[.*\]\s*=\s*//; # chop " [a,b] = " + print "strip []= $line\n" if $trace; + $line =~ s/^\s*\w+\s*=\s*//; # chop " a = " + print "strip a= $line\n" if $trace; + $line =~ s/^\s*\w+\s*\([^\)]*\)\s*//; # chop " f(x) " + print "strip f(x) $line\n" if $trace; + $line =~ s/^\s*[;:]\s*//; # chop " ; " + print "strip ; $line\n" if $trace; + + $line =~ s/^\s*[[:upper:]][[:upper:]0-9_]+//; # chop " BLAH" + print "strip BLAH $line\n" if $trace; + $line =~ s/^\s*\w*\s*[-]+\s+//; # chop " blah --- " + print "strip blah --- $line\n" if $trace; + $line =~ s/^\s*\w+ *\t\s*//; # chop " blah <TAB> " + print "strip blah <TAB> $line\n" if $trace; + $line =~ s/^\s*\w+\s\s+//; # chop " blah " + print "strip blah <NL> $line\n" if $trace; + +# next if $line =~ /^\s*\[/; # skip [a,b] = f(x) +# next if $line =~ /^\s*\w+\s*(=|\()/; # skip a = f(x) OR f(x) + next if $line =~ /^\s*or\s*$/; # skip blah \n or \n blah + next if $line =~ /^\s*$/; # skip blank line + next if $line =~ /^\s?!\//; # skip # !/usr/bin/octave + # XXX FIXME XXX should be testing for unmatched () in proto + # before going to the next line! + last; + } + } + + # Try to make a complete sentence, including the '.' + if ( "$line " !~ /[^.][.]\s/ && $#lines >= 0) { + my $next = $lines[0]; + $line =~ s/\s*$//; # trim trailing blanks on last + $next =~ s/^\s*//; # trim leading blanks on next + $line .= " $next" if "$next " =~ /[^.][.]\s/; # ends the sentence + } + + # Tidy up the sentence. + chomp $line; # trim trailing newline, if there is one + $line =~ s/^\s*//; # trim leading blanks on line + $line =~ s/([^.][.])\s.*$/$1/; # trim everything after the sentence + print "Skipping:\n$desc---\n" if $line eq ""; + + # And return it. + return $line; + +} # 1}}}
new file mode 100644 --- /dev/null +++ b/src/admin/no_vr_val.pm @@ -0,0 +1,45 @@ +#!/usr/bin/perl -w -n + +## Catches vr_val (x) transforms it into varargout(i++) = x; +## + +use OctRe; + +BEGIN { + $first = "vr_val_cnt = 1; "; + +} + +## Does necessary changes inplace on $_[0]. +sub change_line { + + if ($_[0] !~ /^\s*\#/) { # Don't do obvious comment lines + + # Change function declaration + if ($_[0] =~ /$defun_rx/) { + $_[0] =~ s/\.\.\.(\s*\]\s*\=)/varargout$1/g; + } + # Change vr_val() + + # BTW, if 1st vr_val() occurs in a loop, + # this will NOT WORK! + + if ($_[0] =~ + s{vr_val\s*\(([^;]*)\)(\s*;)} + {"$first" . "varargout\{vr_val_cnt++\} = $1$2"}eg) { + + $first = ""; + } + # Did I miss anything? + if ($_[0] =~ /vr_val\s*\(/) { + $_[0] .= "## TODO : Remove this vr_val\n"; + } + + } + $first = "vr_val_cnt = 1; " if $. == 1; +} + +sub comment_line { + "" +} +1;
new file mode 100755 --- /dev/null +++ b/src/admin/octlink.sh @@ -0,0 +1,6 @@ +#! /bin/sh + +FN2=`echo $2 | sed -e's/.octlink//'` +FN1=`echo $1 | sed -e's/.oct//'` +if test -e $2 ; then /bin/rm $2; fi +echo "autoload (\"$FN2\", which (\"$FN1\"));" > $2
new file mode 100755 --- /dev/null +++ b/src/admin/run_forge @@ -0,0 +1,58 @@ +#! /bin/sh + +# Walk the octave-forge tree (starting in the root) searching for +# all the directories that are supposed to be installed. +# Add each directory and any data subdirectories to the LOADPATH for octave. +# Add any bin directories to the EXEC_PATH. +# Add any DLL directories to the system PATH. +# Set LD_LIBRARY_PATH and DYLD_LIBRARY_PATH for any .so and .dylib files found. +# +# You must call this from the root of the octave-forge tree, using, e.g., +# admin/run_forge octave --norc -q +# +# Normally this is called for you, using the run target from make: +# make run + +ROOT=`pwd` +BINPATH="$PATH" +LDPATH="$LD_LIBRARY_PATH" +DYLDPATH="$DYLD_LIBRARY_PATH" +OCTPATH="$OCTAVE_PATH" +# XXX FIXME XXX strictly speaking, the default octave bin directories +# should be in the middle of EXECPATH and PATH, but it should be safe +# to put them at the end since octave probably isn't overriding anything +# on the system. We may also want to pick up the OCTAVE_EXEC_PATH if +# there is one. +EXECPATH="$PATH:" +for f in FIXES main/* extra/* nonfree/*; do + # exclude CVS directories, only include directories, skip NOINSTALL + case "$f" in + */CVS) ;; + *) + if test -d $f -a ! -f $f/NOINSTALL; then + OCTPATH="$ROOT/$f:$OCTPATH" + + # if there is install data, include in on the path + if test -d "$f/data"; then OCTPATH="$ROOT/$f/data:$OCTPATH"; fi + + # make sure we can find supporting binaries + if test -d "$f/bin"; then EXECPATH="$ROOT/$f/bin:$EXECPATH"; fi + if test -d "$f/scripts"; then EXECPATH="$ROOT/$f/scripts:$EXECPATH"; fi + + # supporting libraries need to be available as well + check=`echo $f/*.dll` + if test "$check" != "$f/*.dll"; then BINPATH="$ROOT/$f:$BINPATH"; fi + check=`echo $f/*.so` + if test "$check" != "$f/*.so"; then LDPATH="$ROOT/$f:$LDPATH"; fi + check=`echo $f/*.dylib` + if test "$check" != "$f/*.dylib"; then DYLDPATH="$ROOT/$f:$DYLDPATH"; fi + fi + esac +done +LD_LIBRARY_PATH="$LDPATH" +DYLD_LIBRARY_PATH="$DYLDPATH" +PATH="$BINPATH" +OCTAVE_PATH="$OCTPATH" +OCTAVE_EXEC_PATH="$EXECPATH" +export LD_LIBRARY_PATH DYLD_LIBRARY_PATH PATH OCTAVE_PATH OCTAVE_EXEC_PATH +$*
new file mode 100644 --- /dev/null +++ b/src/admin/template.ndev @@ -0,0 +1,405 @@ +-> Note: this file is a template used by the Perl script 'get_contents'. +-> get_contents reads this file and the CONTENTS files in each +-> subdirectory then creates the new_developer.html file by +-> populating the "Where does your code belong" section. +-> Albert Danial Jan 2 2002 + +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<!-- + The file new_developer.html is generated dynamically by the Perl + program 'get_contents'. Edit admin/template.ndev to make permanent + changes to new_developer.html. + Albert Danial Jan 2 2002 + --> +<html> +<head> +<title>Octave-Forge Developer's Notes</title> + <meta name="keywords" content="instruction,octave,developer,contribute"> +</head> +<body bgcolor="#FFFFFF"> + +<!-- top table {{{1 --> +<table align="center" BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH="95%" BGCOLOR="#444444" > +<tr> +<td> +<table BORDER=0 cellspacing=1 CELLPADDING=3 WIDTH="100%" > +<tr> +<td ALIGN=CENTER VALIGN=CENTER BGCOLOR="#FFFFFF"> + <font face="Arial, Helvetica, Sans Serif" size=+2 color="#0000CC"> + GNU Octave Repository + </font> +</td> +</tr> +</table> +</td> +</tr> +</table> +<p align="center"> +<font size="-1"> +<A href="http://octave.sourceforge.net">Home</A> | +<A href="http://sourceforge.net/projects/octave/">Summary</A> | +<A href="http://sourceforge.net/forum/?group_id=2888">Forums</A> | +<A href="http://sourceforge.net/bugs/?group_id=2888">Bugs</A> | +<A href="http://sourceforge.net/support/?group_id=2888">Support</A> | +<A href="http://sourceforge.net/patch/?group_id=2888">Patches</A> | +<A href="http://sourceforge.net/mail/?group_id=2888">Lists</A> | +<A href="http://sourceforge.net/pm/?group_id=2888">Tasks</A> | +<A href="http://sourceforge.net/docman/?group_id=2888">Docs</A> | +<A href="http://sourceforge.net/survey/?group_id=2888">Surveys</A> | +<A href="http://sourceforge.net/news/?group_id=2888">News</A> | +<A href="http://sourceforge.net/cvs/?group_id=2888">CVS</A> | +<A href="http://sourceforge.net/project/showfiles.php?group_id=2888">Files</A> +</font> +</p> + + +<!-- 1}}} end top table --> + +<p> +<center> +<h2>Contributing Code to the Gnu Octave Repository</h2> +</center> + + +<h3>Requirements</h3> +To contribute your .m files, C++, C, or Fortran code to the GNU Octave +Repository (octave-forge) you need to +<ul> + <li> have an account on SourceForge, + <li> be registered as an octave-forge developer, + <li> have <a href="http://www.cvshome.org/">CVS</a> + installed on the computer from which you + will submit contributions, and + <li> have the secure shell, + <a href="http://www.openssh.com/"><tt>ssh</tt></a>, installed + on your computer. +</ul> +The first two requirements are easy but may take a few days. +If you don't already have one, request a SourceForge (SF) account +<a href="http://sourceforge.net/account/register.php"> here</a>. +To register as a developer send a request +to the octave-forge mailing list +<a href="mailto:octave-dev@lists.sf.net">octave-dev@lists.sf.net</a>. +Include a bit of information about the code +you plan to submit. +Finally, if your computer runs linux or +FreeBSD, chances are good that both <tt>ssh</tt> and CVS are already +installed on your system. +If they aren't, +you will need to find prebuilt packages for them or download their +source codes and build them. + +<h3>Create a SF home directory</h3> +<p> +If you've never submitted code to a SourceForge project before, +create your home directory by +logging onto the octave-forge account with <tt>ssh</tt>: +<pre> + $ ssh -l <FONT COLOR="#800000"><i>sflogin</i></FONT> octave.cvs.sourceforge.net + Password: <FONT COLOR="#800000"><i>your SF password</i></FONT> +</pre> +Although SF will only show you a message-of-the-day screen then log +you out, this process has the useful side effect of creating a home +directory for you if one doesn't already exist. Some CVS commands will fail +if you do not have a home directory on SF. + +<h3>Download the latest octave-forge distribution</h3> +CVS expects the +code you plan to submit to reside in a directory within the existing +octave-forge directory structure. +You will therefore need to download a copy of the latest octave-forge +distribution to work in. Change directories to a place you want +to put the code, then issue the CVS <i>checkout</i> +(abreviated as 'co') command: +<pre> + $ cd <FONT COLOR="#800000"><i>working_directory</i></FONT> + $ export CVS_RSH=ssh + $ cvs -d:ext:<FONT COLOR="#800000"><i>sflogin</i></FONT>@octave.cvs.sourceforge.net:/cvsroot/octave co octave-forge +</pre> + +<h3>Where does your code belong?</h3> + +Put your file(s) in a subdirectory under the <tt>octave-forge/</tt> +directory. Here are some guidelines to help you decide where your +code belongs: +<ul> +>>>INSERT CONTENTS HERE<<< +</ul> + +<h3>Add a copyright notice</h3> +<p> +Each file in octave-forge must contain a copyright notice. +If you wish to release your +code under the +GNU <a href="http://www.gnu.org/licenses/gpl.html">GPL</a> +, insert the following text at the top of your file: +<pre> +## Copyright (C) <FONT COLOR="#800000"><i>year</i></FONT> <FONT COLOR="#800000"><i>Your Name</i></FONT> <<FONT COLOR="#800000"><i>your@preferred.email</i></FONT>> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +</pre> + +Here are other popular open source licenses: +<ul> + <li> <a href="http://www.gnu.org/licenses/lgpl.html">GNU Lesser GPL</a> + <li> <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation License</a> + <li> <a href="http://www.opensource.org/licenses/artistic-license.html">Artistic License</a> + <li> <a href="http://www.opensource.org/licenses/bsd-license.html">BSD License</a> +</ul> +Consult +<a href="http://www.opensource.org/licenses/index.html">opensource.org</a>. +for a comprehensive list of Open Source licenses. + +<h3>Package structure</h3> +<dl> +<dt>package/NOINSTALL +<dd> don't install this package; the user can rename or delete this + file if they want the package installed anyway. +<dt>package/*.m +<dd> m-files for the package; these will be installed in + site/mfiles/octave-forge/package +<dt>package/data/* +<dd> datafiles to be installed with the mfiles. You can accesses + them from your m-files with x = file_in_load_path("a"). +<dt>package/Makefile +<dd> Makefile with a default target to build anything that needs + building, an optional "install" target in case you need to + install something other than m-files, oct-files, data files or + octave binaries, and a "clean" target to remove everything that + has been built. See below for details. +<dt>package/configure.add, package/Makeconf.add +<dd> Additional configuration-time commands to run in order to + find all the components that your package requires. You + can look for anything you want in configure.add and note + what you need in Makeconf.add. The definitions in + Makeconf.add will be available when you include ../../Makeconf + in your Makefile. See main/symbolic for an example. +<dt>package/*.oct +<dd> oct-files built by Makefile. These will be installed all + together in site-oct-files/octave-forge. You may assume that + HAVE_OCTAVE_20 is defined for 2.0.x series mkoctfile, and + HAVE_OCTAVE_21 is defined for 2.1.x series mkoctfile. +<dt>package/bin/* +<dd> executable files built by Makefile. These will be + installed in Octave's EXEC_PATH, so they will be available + from Octave but not from the shell. You have two options + regarding this directory. The better one would be to make + sure that the directory exists before you try building the + binary. The other option is to have a hidden bin/.keepdir + so that CVS won't delete it for you automatically. +</dl> + +<h3>Adding a Makefile</h3> + +If your package has something other than m-files you will need a +Makefile in your directory. This could be as short as three lines: +<pre> +include ../../Makeconf +all: f1.oct +clean: ; -$(RM) *.o core octave-core *.oct *~ +</pre><p> + +If you define multiple DEFUN_DLD's in a file, you may need to +use symbolic links in order for Octave to find them: +<pre> +include ../../Makeconf + +# extra functions defined in fn.oct +fn_LINKS=fn2.oct fn3.oct + +# all compiled functions +PROGS=fn.oct $(fn_LINKS) gn.oct + +all: $(PROGS) + +$(PROGS): Makefile + +$(fn_LINKS): + -$(RM) $@ + $(LN_S) fn.oct $@ + +clean: ; -$(RM) *.o core octave-core *.oct *~ +</pre><p> + +The "include ../../Makeconf" line above includes all of the definitions +that were created during configuration. This includes things like MKOCTFILE, +as well as implicit rules for compiling oct-files. See Makeconf.base +for a list of predefined variables and rules. Sometimes you will see +"sinclude ../../Makeconf". This is for packages which can be compiled +independently of Octave-forge. If Octave-forge is configured, then the +variable OCTAVE_FORGE will be defined.<p> + +Even more complicated makefiles are sometimes necessary, particularly when +the package depends on external libraries. See main/symbolic/Makefile +for an example. The external libraries must be found during configure +so main/symbolic/configure.add provides detection rules. The results +are posted in main/symbolic/Makeconf.add, and will be available during make.<p> + +Please try to keep compatibility with older versions of Octave. The main +configure script tests for features that have changed since octave-2.1.36. +The tests are done in such a way that conditions are only defined if you +are using an older version of octave. That way if the tests are not performed +and the conditions are not defined, support defaults to the newer version +of octave. The following conditions are defined in configure.base: +<dl> +<dt>HAVE_SLLIST_H +<dd>subsref changed from using SLList to using std::list. +To support older versions of octave, use:<pre><code> +#ifdef HAVE_SLLIST_H +#define LIST SLList +#define LISTSIZE length +#define SUBSREF_STRREF +#else +#include <list> +#define LIST std::list +#define LISTSIZE size +#define SUBSREF_STRREF & +#endif +... + octave_value subsref (const std::string SUBSREF_STRREF type, + const LIST<octave_value_list>& idx) { + ... + } + octave_value_list subsref (const std::string SUBSREF_STRREF type, + const LIST<octave_value_list>& idx, + int nargout) { + ... + + if (idx.LISTSIZE () > 1) + ... + } +</code></pre> +<dt>NEED_OCTAVE_QUIT +<dd>signal handling changed from longjump to C++ exceptions. To support +older versions of octave, use:<pre><code> +#ifdef NEED_OCTAVE_QUIT +#define OCTAVE_QUIT do {} while (0) +#define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE +#define END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE +#define octave_throw_bad_alloc() \ + do { jump_to_top_level(); panic_impossible(); } while (0) +#else +#include <octave/quit.h> +#endif +</code></pre> +<dt>USE_OCTAVE_NAN +<dd>octave_NaN and octave_Inf constants were converted to functions. +To support older versions of octave, use:<pre><code> +#ifdef USE_OCTAVE_NAN +#define lo_ieee_nan_value() octave_NaN +#define lo_ieee_inf_value() octave_Inf +#endif +</code></pre> +</dl> +<p>m-file support across multiple versions +is tricky. Sometimes try/catch will help, but for syntax +changes you will need some sort of preprocessor, such as +awk or sed. +</p> + +<h3>Submit your code!</h3> +You are now ready to upload your code to the Gnu Octave Repository. +Do this with two CVS commands--one to add a new +entry for your file in the octave-forge catalog, and a second command +to actually upload the file: +<pre> + $ cvs add <FONT COLOR="#800000"><i>files</i></FONT> + $ cvs commit <FONT COLOR="#800000"><i>files</i></FONT> +</pre> + +After hitting the carriage return at the end of the commit command, +CVS will open your default editor so that you can enter comments about +the commit. The first time you commit a file the comment might be +something as simple as `Initial commit into CVS.' However, for all +subsequent commits please add meaningful comments that explain why +changes were made to the file since all comments will appear in the +changelog. Try to gather related changes into one commit command. +<p> +Aside: the default editor can be defined like so: +<pre> + $ export EDITOR=<FONT COLOR="#800000">vim</FONT> +</pre> +<p> + +If you are uploading an entire package, then put your directory into the +octave-forge tree and do the following: +<pre> + $ cd octave-forge/main + $ cvs add <FONT COLOR="#800000"><i>package</i></FONT> + $ cvs commit <FONT COLOR="#800000"><i>package</i></FONT> + $ cd <FONT COLOR="#800000"><i>package</i></FONT> + $ cvs add * + $ cvs commit * +</pre> + +You may find it easier to use the import command, especially if your +package contains subdirectories. In this case, you should not put +your directory into the octave-forge tree. Instead, change to the +root of your package tree and enter the following: +<pre> + $ cd <FONT COLOR="#800000"><i>package</i></FONT> + $ cvs -d:ext:<FONT COLOR="#800000"><i>sflogin</i></FONT>@octave.cvs.sourceforge.net:/cvsroot/octave import -m "<FONT COLOR="#800000"><i>package name</i></FONT>" octave-forge/<FONT COLOR="#800000"><i>main/package</i></FONT> <FONT COLOR="#800000"><i>sflogin</i></FONT> start +</pre> + +You can then fetch the new package from octave-forge as follows: +<pre> + $ cd octave-forge + $ cvs -q update -d +</pre> + +<p> +From time to time, you will need to synchronize with CVS: +<pre> + $ cd octave-forge + $ cvs -q update -d +</pre> +Each file will be listed with one of the following codes: +<ul> +<li> `?' for files you created didn't add and commit. +<li> `M' for files you modified but didn't commit. +<li> `C' for files which have unresolvable conflicts. Look inside the file to +see what it was that couldn't be resolved. It will be clearly marked, or you +can do a cvs diff on the file to highlight the conflict. +<li> `U' for files you haven't touched but are modified on the server. +<li> `P' for files you have modified in a way consistent with the modifications +on the server (?), e.g., because you submitted a patch for someone else to apply. +</ul> + +<h3>Learn more about CVS</h3> +The few CVS commands shown here just scratch the surface of this +powerful versioning package. If you become an active contributor +you will benefit from learning more CVS commands and understanding +how CVS works. +The +<a href="http://cvsbook.red-bean.com/cvsbook.html"> +CVS Book</a> is a great place to begin your exploration. + +<h3>Join the developers' mailing list</h3> +Finally, consider joining the octave-forge developer's +<a href="http://lists.sourceforge.net/lists/listinfo/octave-dev"> +mailing list</a>. It is very low traffic. It is used to announce +pending releases of octave-forge and discuss issues related to +working with octave-forge. Discussion of the functions in +octave-forge mostly occurs on the primary octave mailing lists. + +<hr noshade size=1> + +<center> +<p> +<small>Hosted by</small> +<br><a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=2888&type=4" width="125" height="37" border="0" alt="SourceForge.net Logo" /></a> + +</body> +</html>
new file mode 100644 --- /dev/null +++ b/src/admin/template.readme @@ -0,0 +1,137 @@ +-> Note: this is not the true README file. Create the correct top-level +-> README by running the Perl script 'get_contents'. get_contents +-> reads this file and the CONTENTS files in each subdirectory then +-> creates the README by populating the "Project organization" +-> section below with the information found in the CONTENTS files. +-> Albert Danial Jan 2 2002 + +*** README is automatically generated from admin/template.readme *** + +The octave-forge project contains functions for Octave which are not in +the main distribution. While the main Octave distribution is +conservative about accepting new functions and changes, octave-forge is +very open. As a result, be prepared for some lower quality code and +more rapidly changing interfaces to the functions in octave-forge. + +The collection is in the public domain, but the individual functions +vary. See COPYING for details. See INSTALL for installation +instructions. + +Octave needs your support! Please donate to the University of +Wisconsin Foundation: + + http://www.uwfoundation.wisc.edu/index.html + +designated as follows: + + I/we wish to support ongoing development of the Octave modelling + language, under the supervision of Professor James B. Rawlings and + Dr. John W. Eaton of the Department of Chemical and Biological + Engineering at the University of Wisconsin-Madison. + +Donations are tax deductible in the United States. A donation of $10/user +per year at current estimates of the user base would support two developers. +Adjust as appropriate for the percentage of users that you think will donate. + + +===================================================================== +Project organization +====================================================================== +Package organization + +package/NOINSTALL + don't install this package; rename or delete this + file if you want the package installed anyway. +package/INDEX + a functions in the directory organized into categories. See + octave-forge/INDEX for a description of the format. +package/*.m + m-files for the package. These will be installed in + site/mfiles/octave-forge/package +package/data/* + datafiles to be installed with the mfiles. You can accesses + them from your m-files with x = file_in_load_path("a"). +package/Makefile + Makefile with a default target to build anything that needs + building, an "install" target to install anything that needs + installing (other than oct-files and m-files---they are handled + automatically), and a "clean" target to delete everything that + was built. +package/configure.add +package/Makeconf.add + Additional configuration-time commands to run in order to + find all the components that the package requires. +package/*.oct + oct-files built by Makefile. These will be installed all + together in site-oct-files/octave-forge. +package/bin/* + executable files built by Makefile. These will be + installed in Octave's EXEC_PATH, so they will be available + from Octave but not from the shell. + +========================================================================== +Administrative files + +autogen.sh + Generates ./configure and Makeconf.in + +configure.base +Makeconf.base + Basic configuration checks, such as locating the install paths, + and the associated variables to be put into Makeconf. Each + package can append checks by including configure.add in the + package directory. + +octinst.sh.in + Install program for packages, with pieces to be filed in by + ./configure + +install-sh + intall program to use if /usr/bin/install does not work + +COPYING + License for the collection, plus an out-of-date list of functions + in the collection and their licenses. + +COPYING.GPL + The text of the GPL license + +cvs-tree + Generate web listing of m-files in the tree + +README + This file + +TODO + Things that could/should be done + +INSTALL + Installation instructions + +Makefile + Top level makefile + +release.sh + Generates release tarball + +cvsdir.sh + Save/restore CVS adminstration files. You need this to install + directly from the CVS tree rather than an exported tarball. E.g., + $ cvsdir.sh save + $ make install + $ cvsdir.sh restore + +========================================================================== +Compatibility Issues + +Issue the following command: + $ grep -d skip "XXX COMPATIBILITY XXX" */* */*/* +for a list of compatibility issues in various functions. As of this +writing, mu2lin is a likely cause of problems when porting audio +packages. + + +========================================================================== +Paul Kienzle +pkienzle@users.sf.net +March 17, 2002
new file mode 100755 --- /dev/null +++ b/src/autogen.sh @@ -0,0 +1,33 @@ +#! /bin/sh + +## Generate ./configure +rm -f configure.in +echo "dnl --- DO NOT EDIT --- Automatically generated by autogen.sh" > configure.in +cat configure.base >> configure.in +files=`find . -name configure.add -print` +if test ! -z "$files" ; then + cat $files >> configure.in +fi +cat <<EOF >> configure.in + AC_OUTPUT(\$CONFIGURE_OUTPUTS) + dnl XXX FIXME XXX chmod is not in autoconf's list of portable functions + chmod 0771 octinst.sh + echo " " + echo " \"\\\$prefix\" is \$prefix" + echo " \"\\\$exec_prefix\" is \$exec_prefix" + AC_MSG_RESULT([\$STATUS_MSG + +find . -name NOINSTALL -print # shows which toolboxes won't be installed +]) +EOF + +autoconf && rm -f configure.in + +## Generate ./Makeconf.in +rm -f Makeconf.in +cp Makeconf.base Makeconf.in +files=`find . -name Makeconf.add -print` +if test ! -z "$files" ; then + cat $files >> Makeconf.in +fi +
new file mode 100644 --- /dev/null +++ b/src/bwfill.cc @@ -0,0 +1,241 @@ +/* + * BWFILL: fill a bw image starting at points + * imo= block(im, xregs, yregs); + * + * Copyright (C) 1999 Andy Adler + * This code has no warrany whatsoever. + * Do what you like with this code as long as you + * leave this copyright in place. + * + * $Id$ + */ + +#include <octave/oct.h> + +#ifndef OCTAVE_LOCAL_BUFFER +#include <vector> +#define OCTAVE_LOCAL_BUFFER(T, buf, size) \ + std::vector<T> buf ## _vector (size); \ + T *buf = &(buf ## _vector[0]) +#endif + +#define ptUP (-1) +#define ptDN (+1) +#define ptRT (+ioM) +#define ptLF (-ioM) + +/* + * check if the point needs to be filled, if so + * fill it and change the appropriate variables + */ +void checkpoint( int pt, + unsigned char* imo, + int * ptstack, + int * npoints ) { +// printf("filling %d np=%d fill=%d\n",pt,*npoints, *(imo+pt)==0 ); + if( *(imo+pt) != 0 ) return; + + *(imo+pt) = 2; + *(ptstack + (*npoints))= pt; + (*npoints)++; +} + +DEFUN_DLD (bwfill, args, , + "[...] = bwfill (...)\n\ + [BW2,IDX] = BWFILL(BW1,Y,X,N) performs a flood-fill on BW1\n\ +\n\ + (X(k), Y(k)) are rows and columns of seed points\n\ +\n\ + [BW2,IDX] = BWFILL(BW1,'holes',N) fills interior holes in BW1\n\ +\n\ + N = 4 or 8(default) for neighborhood connectedness\n\ +\n\ + IDX is the indices of the filled pixels") +{ + octave_value_list retval; + octave_value tmp; + ColumnVector xseed, yseed ; + int nargin = args.length (); + + if (nargin < 2 ) { + print_usage (); + return retval; + } + + Matrix im= args(0).matrix_value(); + int imM= im.rows(); + int imN= im.columns(); + + int nb= 8; + int npoints= 0; + bool fillmode= false; + if (args(1).is_string() && args(1).string_value() == "holes" ) { + fillmode= true; + + npoints= 2*( imM + imN - 4 ); // don't start fill from corners + + xseed= ColumnVector( npoints ); + yseed= ColumnVector( npoints ); + int idx= 0; + for (int j=2; j<= imN-1; j++) { + xseed( idx )= j; yseed( idx++)= 1; + xseed( idx )= j; yseed( idx++)= imM; + } + + for (int i=2; i<= imM-1; i++) { + yseed( idx )= i; xseed( idx++)= 1; + yseed( idx )= i; xseed( idx++)= imN; + } + + if (nargin >= 4 ) + nb= (int) args(2).double_value(); + } // holes mode? + else { + { + ColumnVector tmp( args(2).vector_value() ); + xseed= tmp; + } + { + ColumnVector tmp( args(1).vector_value() ); + yseed= tmp; + } + npoints= xseed.length(); + if (nargin >= 4 ) + nb= (int) args(3).double_value(); + } // holes mode? + +/* + * put a one pixel thick boundary around the image + * so that we can be more efficient in the main loop + */ + int ioM= imM+2; + OCTAVE_LOCAL_BUFFER(unsigned char, imo, (imM+2) * (imN+2)); + + for (int i=0; i<imM; i++) + for (int j=0; j<imN; j++) + imo[(i+1) + ioM*(j+1)]= ( im(i,j) > 0 ) ; + + for (int i=0; i<ioM; i++) + imo[i]= imo[i + ioM*(imN+1)] = 3; + + for (int j=1; j<imN+1; j++) + imo[ioM*j]= imo[imM+1 + ioM*j] = 3; + +// This is obviously big enough for the point stack, but I'm +// sure it can be smaller. + OCTAVE_LOCAL_BUFFER(int, ptstack, ioM*imN ); + + int seedidx= npoints; + npoints= 0; + while ( (--seedidx) >= 0 ) { +// no need to add 1 to convert indexing style because we're adding a boundary + int pt= (int) xseed( seedidx )*ioM + (int) yseed( seedidx ); + checkpoint( pt , imo, ptstack, &npoints ); + } + + while ( npoints > 0 ) { + npoints--; + int pt= ptstack[ npoints ]; + + checkpoint( pt + ptLF, imo, ptstack, &npoints ); + checkpoint( pt + ptRT, imo, ptstack, &npoints ); + checkpoint( pt + ptUP, imo, ptstack, &npoints ); + checkpoint( pt + ptDN, imo, ptstack, &npoints ); + + if (nb==8) { + checkpoint( pt + ptLF + ptUP, imo, ptstack, &npoints ); + checkpoint( pt + ptRT + ptUP, imo, ptstack, &npoints ); + checkpoint( pt + ptLF + ptDN, imo, ptstack, &npoints ); + checkpoint( pt + ptRT + ptDN, imo, ptstack, &npoints ); + } + } // while ( npoints + + Matrix imout( imM, imN ); + ColumnVector idxout (imM*imN ); + int idx=0; + + int notvalidpt= 0; + int idxpoint= 2; + if ( fillmode ) { + notvalidpt= 2; + idxpoint= 0; + } + + for (int i=0; i<imM; i++) + for (int j=0; j<imN; j++) { + imout(i,j) = (double) ( imo[(i+1) + ioM*(j+1)] != notvalidpt ); + if ( imo[(i+1) + ioM*(j+1)] == idxpoint ) + idxout(idx++) = (double) (i + j*imM + 1); + } + + /* + Matrix imout( imM+2, imN+2 ); + for (int i=0; i<imM+2; i++) + for (int j=0; j<imN+2; j++) + imout(i,j) = (double) imo[i + ioM*j]; + */ + + retval(0)= imout; +// we need to do this to be able to return a proper empty vector + if (idx > 0) + retval(1)= idxout.extract(0, idx-1); + else + retval(1)= ColumnVector ( 0 ); + return retval; +} + + +/* + * $Log$ + * Revision 1.1 2006/08/20 12:59:36 hauberg + * Changed the structure to match the package system + * + * Revision 1.7 2006/05/19 06:58:50 jwe + * *** empty log message *** + * + * Revision 1.5 2003/05/15 21:25:40 pkienzle + * OCTAVE_LOCAL_BUFFER now requires #include <memory> + * + * Revision 1.4 2003/03/05 15:31:52 pkienzle + * Backport to octave-2.1.36 + * + * Revision 1.3 2003/02/20 23:03:57 pkienzle + * Use of "T x[n]" where n is not constant is a g++ extension so replace it with + * OCTAVE_LOCAL_BUFFER(T,x,n), and other things to keep the picky MipsPRO CC + * compiler happy. + * + * Revision 1.2 2002/11/02 10:39:36 pkienzle + * gcc 3.2 wants \n\ for multi-line strings. + * + * Revision 1.1 2002/03/17 02:38:51 aadler + * fill and edge detection operators + * + * Revision 1.9 2000/06/16 20:22:47 aadler + * mods for 2.1/2.0 compat + * + * Revision 1.8 2000/06/13 17:27:24 aadler + * mods for 2.1.30 + * + * Revision 1.7 1999/06/10 19:42:12 aadler + * minor verbose fix + * + * Revision 1.6 1999/06/08 16:30:30 aadler + * bug fix. reversed r,c input arguments + * + * Revision 1.5 1999/06/08 15:41:02 aadler + * now fills in holes + * + * Revision 1.4 1999/06/08 15:21:02 aadler + * fixed bug that so specified points are only used if they can fill + * + * Revision 1.3 1999/06/08 15:05:08 aadler + * now returns 1 and gives index output + * + * Revision 1.2 1999/06/04 21:58:57 aadler + * fixed 8 vs 4 neighborhood + * + * Revision 1.1 1999/06/04 21:43:20 aadler + * Initial revision + * + * + */
new file mode 100644 --- /dev/null +++ b/src/bwlabel.cc @@ -0,0 +1,238 @@ +/* --------------------------------------------------------------------- + + bwimage.cc - octave module to label componenets of a binary image + + copyright 2002 Jeffrey E. Boyd + + - uses 4, 6, or 8 connectedness + - See BKP Horn, Robot Vision, MIT Press, 1986, p 66 - 71 + + labeling scheme + + +-+-+-+ + |D|C|E| + +-+-+-+ + |B|A| | + +-+-+-+ + | | | | + +-+-+-+ + + A is the center pixel of a neighborhood. In the 3 versions of + connectedness: + + 4: A connects to B and C + 6: A connects to B, C, and D + 8: A connects to B, C, D, and E + + +--------------------------------------------------------------------- */ + + + +#include <oct.h> +#ifndef OCTAVE_LOCAL_BUFFER +#include <vector> +#define OCTAVE_LOCAL_BUFFER(T, buf, size) \ + std::vector<T> buf ## _vector (size); \ + T *buf = &(buf ## _vector[0]) +#endif + + + +#define NO_OBJECT 0 +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + + + +static int find( int *, int ); + +static bool any_bad_argument( const octave_value_list& ); + + +/* +%!assert(bwlabel([0 1 0; 0 0 0; 1 0 1]),[0 1 0; 0 0 0; 2 0 3]); +*/ +DEFUN_DLD(bwlabel, args, , +"\n\ +[l,num] = bwlabel( bw, n ) - label foreground components of boolean image\n\ +\n\ + bw - boolean image array\n\ + n - neighborhood connectedness (4, 6,or 8)\n\ +\n\ + l - label image array\n\ + num - number of components labeled\n\ +\n\ + The algorithm is derived from BKP Horn, Robot Vision, MIT Press,\n\ + 1986, p 65 - 89 \n" ) +{ + if ( any_bad_argument(args) ) + return octave_value_list(); + + // input arguments + Matrix BW = args(0).matrix_value(); // the input binary image + int n; + if ( args.length() < 2 ) n = 6; // n-hood connectivity + else n = args(1).int_value(); + int nr = args(0).rows(); + int nc = args(0).columns(); + + // results + Matrix L( nr, nc ); // the label image + int nobj; // number of objects found in image + + // other variables + int ntable; // number of elements in the component table/tree + + OCTAVE_LOCAL_BUFFER(int, lset, nr * nc); // label table/tree + ntable = 0; + lset[0] = 0; + + for( int r = 0; r < nr; r++ ) { + for( int c = 0; c < nc; c++ ) { + if ( BW.elem(r,c) ) { // if A is an object + // get the neighboring pixels B, C, D, and E + int B, C, D, E; + if ( c == 0 ) B = 0; else B = find( lset, (int)L.elem(r,c-1) ); + if ( r == 0 ) C = 0; else C = find( lset, (int)L.elem(r-1,c) ); + if ( r == 0 || c == 0 ) D = 0; else D = find( lset, (int)L.elem(r-1,c-1) ); + if ( r == 0 || c == nc - 1 ) E = 0; + else E = find( lset, (int)L.elem(r-1,c+1) ); + + if ( n == 4 ) { + // apply 4 connectedness + if ( B && C ) { // B and C are labeled + if ( B == C ) + L.elem(r,c) = B; + else { + lset[C] = B; + L.elem(r,c) = B; + } + } else if ( B ) // B is object but C is not + L.elem(r,c) = B; + else if ( C ) // C is object but B is not + L.elem(r,c) = C; + else { // B, C, D not object - new object + // label and put into table + ntable++; + L.elem(r,c) = lset[ ntable ] = ntable; + } + } else if ( n == 6 ) { + // apply 6 connected ness + if ( D ) // D object, copy label and move on + L.elem(r,c) = D; + else if ( B && C ) { // B and C are labeled + if ( B == C ) + L.elem(r,c) = B; + else { + int tlabel = MIN(B,C); + lset[B] = tlabel; + lset[C] = tlabel; + L.elem(r,c) = tlabel; + } + } else if ( B ) // B is object but C is not + L.elem(r,c) = B; + else if ( C ) // C is object but B is not + L.elem(r,c) = C; + else { // B, C, D not object - new object + // label and put into table + ntable++; + L.elem(r,c) = lset[ ntable ] = ntable; + } + } else if ( n == 8 ) { + // apply 8 connectedness + if ( B || C || D || E ) { + int tlabel = B; + if ( B ) tlabel = B; + else if ( C ) tlabel = C; + else if ( D ) tlabel = D; + else if ( E ) tlabel = E; + L.elem(r,c) = tlabel; + if ( B && B != tlabel ) lset[B] = tlabel; + if ( C && C != tlabel ) lset[C] = tlabel; + if ( D && D != tlabel ) lset[D] = tlabel; + if ( E && E != tlabel ) lset[E] = tlabel; + } else { + // label and put into table + ntable++; + L.elem(r,c) = lset[ ntable ] = ntable; + } + } + } else { + L.elem(r,c) = NO_OBJECT; // A is not an object so leave it + } + } + } + + // consolidate component table + for( int i = 0; i <= ntable; i++ ) + lset[i] = find( lset, i ); + + // run image through the look-up table + for( int r = 0; r < nr; r++ ) + for( int c = 0; c < nc; c++ ) + L.elem(r,c) = lset[ (int)L.elem(r,c) ]; + + // count up the objects in the image + for( int i = 0; i <= ntable; i++ ) + lset[i] = 0; + + for( int r = 0; r < nr; r++ ) + for( int c = 0; c < nc; c++ ) + lset[ (int)L.elem(r,c) ]++; + + // number the objects from 1 through n objects + nobj = 0; + lset[0] = 0; + for( int i = 1; i <= ntable; i++ ) + if ( lset[i] > 0 ) + lset[i] = ++nobj; + + // run through the look-up table again + for( int r = 0; r < nr; r++ ) + for( int c = 0; c < nc; c++ ) + L.elem(r,c) = lset[ (int)L.elem(r,c) ]; + + octave_value_list rval; + rval(0) = L; + rval(1) = (double)nobj; + return rval; +} + + +static bool any_bad_argument( const octave_value_list& args ) +{ + if ( args.length() < 1 || args.length() > 2 ) { + error( "bwlabel: number of arguments - expecting bwlabel(bw) or bwlabel(bw,n)" ); + return true; + } + + if ( !args(0).is_matrix_type() ) { + error( "bwlabel: matrix expected for first argument" ); + return true; + } + + if ( args.length() == 2 ) { + if ( !args(1).is_real_scalar() ) { + error( "bwlabel: expecting real scalar for second argument" ); + return true; + } + int n = args(1).int_value(); + if ( n != 4 && n != 6 && n != 8 ) { + error( "bwlabel: in bwlabel(BW,n) n must be in {4,6,8}" ); + return true; + } + } + + return false; + +} + + +static int find( int set[], int x ) +{ + int r = x; + while ( set[r] != r ) + r = set[r]; + return r; +} +
new file mode 100644 --- /dev/null +++ b/src/configure.add @@ -0,0 +1,56 @@ + +if test -e main/image/NOINSTALL ; then + + dnl Not installing so don't test for libjpeg/libpng/libMagick++. + STATUS=none + +else + + AC_DEFINE(have_jpeg) + AC_CHECK_HEADER(jpeglib.h, have_jpeg=yes, have_jpeg=no) + if test $have_jpeg = yes ; then + OF_CHECK_LIB(jpeg, jpeg_std_error, have_jpeg=yes, have_jpeg=no) + if test $have_jpeg = no ; then + STATUS="libjpeg not found" + else + STATUS="jpeg" + AC_SUBST(DEFHAVE_JPEG) + DEFHAVE_JPEG="HAVE_JPEG=1" + fi + else + STATUS="jpeglib.h not found" + fi + + AC_DEFINE(have_png) + AC_CHECK_HEADER(png.h, have_png=yes, have_png=no) + if test $have_png = yes ; then + OF_CHECK_LIB(png, png_set_sig_bytes, have_png=yes, have_png=no) + if test $have_png = no ; then + STATUS="$STATUS, libpng not found" + else + STATUS="$STATUS, png" + AC_SUBST(DEFHAVE_PNG) + DEFHAVE_PNG="HAVE_PNG=1" + fi + else + STATUS="$STATUS, png.h not found" + fi + + AC_CHECK_PROG(HAVE_MAGICKXX, Magick++-config, yes) + if test $HAVE_MAGICKXX ; then + STATUS="$STATUS, ImageMagick++" + AC_SUBST(DEFHAVE_MAGICKXX) + DEFHAVE_MAGICKXX="HAVE_MAGICKXX=1" + else + STATUS="$STATUS, ImageMagick++ not found" + fi + + +fi + +dnl Append the status message to the global status message. This will +dnl be displayed at the end of configuration so that the user doesn't +dnl have to scan the list for critical details. + +STATUS_MSG="$STATUS_MSG + read/write image formats: $STATUS"
new file mode 100644 --- /dev/null +++ b/src/configure.base @@ -0,0 +1,520 @@ +dnl The configure script is generated by autogen.sh from configure.base +dnl and the various configure.add files in the source tree. Edit +dnl configure.base and reprocess rather than modifying ./configure. + +dnl autoconf 2.13 certainly doesn't work! What is the minimum requirement? +AC_PREREQ(2.2) + +AC_INIT(configure.base) + +PACKAGE=octave-forge +MAJOR_VERSION=0 +MINOR_VERSION=1 +PATCH_LEVEL=0 + +dnl Kill caching --- this ought to be the default +define([AC_CACHE_LOAD], )dnl +define([AC_CACHE_SAVE], )dnl + +dnl uncomment to put support files in another directory +dnl AC_CONFIG_AUX_DIR(admin) + +VERSION=$MAJOR_VERSION.$MINOR_VERSION.$PATCH_LEVEL +AC_SUBST(PACKAGE) +AC_SUBST(VERSION) + +dnl need to find admin files, so keep track of the top dir. +TOPDIR=`pwd` +AC_SUBST(TOPDIR) + +dnl if mkoctfile doesn't work, then we need the following: +dnl AC_PROG_CXX +dnl AC_PROG_F77 + +dnl Need C compiler regardless so define it in a way that +dnl makes autoconf happy and we can override whatever we +dnl need with mkoctfile -p. +dnl XXX FIXME XXX should use mkoctfile to get CC and CFLAGS +AC_PROG_CC + +dnl XXX FIXME XXX need tests for -p -c -s in mkoctfile. + +dnl ******************************************************************* +dnl Sort out mkoctfile version number and install paths + +dnl XXX FIXME XXX latest octave has octave-config so we don't +dnl need to discover things here. Doesn't have --exe-site-dir +dnl but defines --oct-site-dir and --m-site-dir + +dnl Check for mkoctfile +AC_CHECK_PROG(MKOCTFILE,mkoctfile,mkoctfile) +test -z "$MKOCTFILE" && AC_MSG_WARN([no mkoctfile found on path]) + +AC_SUBST(ver) +AC_SUBST(subver) +AC_SUBST(mpath) +AC_SUBST(opath) +AC_SUBST(xpath) +AC_SUBST(altpath) +AC_SUBST(altmpath) +AC_SUBST(altopath) + +AC_ARG_WITH(path, + [ --with-path install path prefix], + [ path=$withval ]) +AC_ARG_WITH(mpath, + [ --with-mpath override path for m-files], + [mpath=$withval]) +AC_ARG_WITH(opath, + [ --with-opath override path for oct-files], + [opath=$withval]) +AC_ARG_WITH(xpath, + [ --with-xpath override path for executables], + [xpath=$withval]) +AC_ARG_WITH(altpath, + [ --with-altpath alternative functions install path prefix], + [ altpath=$withval ]) +AC_ARG_WITH(altmpath, + [ --with-altmpath override path for alternative m-files], + [altmpath=$withval]) +AC_ARG_WITH(altopath, + [ --with-altopath override path for alternative oct-files], + [altopath=$withval]) + +if test -n "$path" ; then + test -z "$mpath" && mpath=$path + test -z "$opath" && opath=$path/oct + test -z "$xpath" && xpath=$path/bin + test -z "$altpath" && altpath=$path-alternatives +fi + +if test -n "$altpath" ; then + test -z "$altmpath" && altmpath=$altpath + test -z "$altopath" && altopath=$altpath/oct +fi + +dnl Don't query if path/ver are given in the configure environment +#if test -z "$mpath" || test -z "$opath" || test -z "$xpath" || test -z "$altmpath" || test -z "$altopath" || test -z "$ver" ; then +if test -z "$mpath" || test -z "$opath" || test -z "$xpath" || test -z "$ver" ; then + dnl Construct program to get mkoctfile version and local install paths + cat > conftest.cc <<EOF +#include <octave/config.h> +#include <octave/version.h> +#include <octave/defaults.h> + +#define INFOV "\nINFOV=" OCTAVE_VERSION "\n" + +#define INFOH "\nINFOH=" OCTAVE_CANONICAL_HOST_TYPE "\n" + +#ifdef OCTAVE_LOCALVERFCNFILEDIR +# define INFOM "\nINFOM=" OCTAVE_LOCALVERFCNFILEDIR "\n" +#else +# define INFOM "\nINFOM=" OCTAVE_LOCALFCNFILEPATH "\n" +#endif + +#ifdef OCTAVE_LOCALVEROCTFILEDIR +# define INFOO "\nINFOO=" OCTAVE_LOCALVEROCTFILEDIR "\n" +#else +# define INFOO "\nINFOO=" OCTAVE_LOCALOCTFILEPATH "\n" +#endif + +#ifdef OCTAVE_LOCALVERARCHLIBDIR +# define INFOX "\nINFOX=" OCTAVE_LOCALVERARCHLIBDIR "\n" +#else +# define INFOX "\nINFOX=" OCTAVE_LOCALARCHLIBDIR "\n" +#endif + +const char *infom = INFOM; +const char *infoo = INFOO; +const char *infox = INFOX; +const char *infoh = INFOH; +const char *infov = INFOV; +EOF + + dnl Compile program perhaps with a special version of mkoctfile + $MKOCTFILE conftest.cc || AC_MSG_ERROR(Could not run $MKOCTFILE) + + dnl Strip the config info from the compiled file + eval `strings conftest.o | grep "^INFO.=" | sed -e "s,//.*$,,"` + rm -rf conftest* + + dnl set the appropriate variables if they are not already set + ver=`echo $INFOV | sed -e "s/\.//" -e "s/\..*$//"` + subver=`echo $INFOV | sed -e "[s/^[^.]*[.][^.]*[.]//]"` + alt_mbase=`echo $INFOM | sed -e "[s,\/[^\/]*$,,]"` + alt_obase=`echo $INFOO | sed -e "[s,/site.*$,/site,]"` + test -z "$mpath" && mpath=$INFOM/octave-forge + test -z "$opath" && opath=$INFOO/octave-forge + test -z "$xpath" && xpath=$INFOX + test -z "$altmpath" && altmpath=$alt_mbase/octave-forge-alternatives/m + test -z "$altopath" && altopath=$alt_obase/octave-forge-alternatives/oct/$INFOH +fi + +dnl ******************************************************************* + +dnl XXX FIXME XXX Should we allow the user to override these? +dnl Do we even need them? The individual makefiles can call mkoctfile -p +dnl themselves, so the only reason to keep them is for configure, and +dnl for those things which are not built using mkoctfile (e.g., aurecord) +dnl but it is not clear we should be using octave compile flags for those. + +dnl C compiler and flags +AC_MSG_RESULT([retrieving compile and link flags from $MKOCTFILE]) +CC=`$MKOCTFILE -p CC` +CFLAGS=`$MKOCTFILE -p CFLAGS` +CPPFLAGS=`$MKOCTFILE -p CPPFLAGS` +CPICFLAG=`$MKOCTFILE -p CPICFLAG` +LDFLAGS=`$MKOCTFILE -p LDFLAGS` +LIBS=`$MKOCTFILE -p LIBS` +AC_SUBST(CC) +AC_SUBST(CFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(CPICFLAG) + +dnl Fortran compiler and flags +F77=`$MKOCTFILE -p F77` +FFLAGS=`$MKOCTFILE -p FFLAGS` +FPICFLAG=`$MKOCTFILE -p FPICFLAG` +AC_SUBST(F77) +AC_SUBST(FFLAGS) +AC_SUBST(FPICFLAG) + +dnl C++ compiler and flags +CXX=`$MKOCTFILE -p CXX` +CXXFLAGS=`$MKOCTFILE -p CXXFLAGS` +CXXPICFLAG=`$MKOCTFILE -p CXXPICFLAG` +AC_SUBST(CXX) +AC_SUBST(CXXFLAGS) +AC_SUBST(CXXPICFLAG) + +dnl ******************************************************************* + +dnl Check for features of your version of mkoctfile. +dnl All checks should be designed so that the default +dnl action if the tests are not performed is to do whatever +dnl is appropriate for the most recent version of Octave. + +dnl Define the following macro: +dnl OF_CHECK_LIB(lib,fn,true,false,helpers) +dnl This is just like AC_CHECK_LIB, but it doesn't update LIBS +AC_DEFUN(OF_CHECK_LIB, +[save_LIBS="$LIBS" +AC_CHECK_LIB($1,$2,$3,$4,$5) +LIBS="$save_LIBS" +]) + +dnl Define the following macro: +dnl TRY_MKOCTFILE(msg,program,action_if_true,action_if_false) +dnl +AC_DEFUN(TRY_MKOCTFILE, +[AC_MSG_CHECKING($1) +cat > conftest.cc << EOF +#include <octave/config.h> +$2 +EOF +ac_try="$MKOCTFILE -c conftest.cc" +if AC_TRY_EVAL(ac_try) ; then + AC_MSG_RESULT(yes) + $3 +else + AC_MSG_RESULT(no) + $4 +fi +]) + +dnl +dnl Check if F77_FUNC works with MKOCTFILE +dnl +TRY_MKOCTFILE([for F77_FUNC], +[int F77_FUNC (hello, HELLO) (const int &n);],, +[MKOCTFILE="$MKOCTFILE -DF77_FUNC=F77_FCN"]) + +dnl +dnl Check if octave still uses SLList.h +dnl +TRY_MKOCTFILE([for SLList.h],[#include <octave/SLList.h>], +[MKOCTFILE="$MKOCTFILE -DHAVE_SLLIST_H"],) + +dnl +dnl Check if octave has lo_ieee_nan_value +dnl +TRY_MKOCTFILE([for lo_ieee_nan_value], +[ #include <octave/lo-ieee.h> +int test(void) { lo_ieee_nan_value(); }],, +[MKOCTFILE="$MKOCTFILE -DUSE_OCTAVE_NAN"]) + +dnl +dnl Check if octave is needs octave_idx_type +dnl +TRY_MKOCTFILE([for octave_idx_type], +[#include <octave/oct-types.h> +octave_idx_type test(void) { octave_idx_type idx = 1; return idx; }],, +[MKOCTFILE="$MKOCTFILE -Doctave_idx_type=int"]) + +dnl +dnl Check if octave uses quit.h +dnl +TRY_MKOCTFILE([for quit.h],[#include <octave/quit.h>],, +[MKOCTFILE="$MKOCTFILE -DNEED_OCTAVE_QUIT"]) + +dnl ********************************************************** + +dnl Evaluate an expression in octave +dnl +dnl OCTAVE_EVAL(expr,var) -> var=expr +dnl +AC_DEFUN(OCTAVE_EVAL, +[AC_MSG_CHECKING([for $1 in Octave]) +$2=`echo "disp($1)" | $OCTAVE -qf` +AC_MSG_RESULT($$2) +AC_SUBST($2) +]) + +dnl Check status of an octave variable +dnl +dnl OCTAVE_CHECK_EXIST(variable,action_if_true,action_if_false) +dnl +AC_DEFUN(OCTAVE_CHECK_EXIST, +[AC_MSG_CHECKING([for $1 in Octave]) +if test `echo 'disp(exist("$1"))' | $OCTAVE -qf`X != 0X ; then + AC_MSG_RESULT(yes) + $2 +else + AC_MSG_RESULT(no) + $3 +fi +]) + +dnl should check that $(OCTAVE) --version matches $(MKOCTFILE) --version +AC_CHECK_PROG(OCTAVE,octave,octave) +OCTAVE_EVAL(OCTAVE_VERSION,OCTAVE_VERSION) + +dnl grab canonical host type so we can write system specific install stuff +OCTAVE_EVAL(octave_config_info('canonical_host_type'),canonical_host_type) + +dnl grab SHLEXT from octave config +OCTAVE_EVAL(octave_config_info('SHLEXT'),SHLEXT) + +AC_PROG_LN_S +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl Use $(COPY_FLAGS) to set options for cp when installing .oct files. +COPY_FLAGS="-Rfp" +case "$canonical_host_type" in + *-*-linux*) + COPY_FLAGS="-fdp" + ;; +esac +AC_SUBST(COPY_FLAGS) + +dnl Use $(STRIP) in the makefile to strip executables. If not found, +dnl STRIP expands to ':', which in the makefile does nothing. +dnl Don't need this for .oct files since mkoctfile handles them directly +STRIP=${STRIP-strip} +AC_CHECK_PROG(STRIP,$STRIP,$STRIP,:) + +dnl Strip on windows, don't strip on Mac OS/X or IRIX +dnl For the rest, you can force strip using MKOCTFILE="mkoctfile -s" +dnl or avoid strip using STRIP=: before ./configure +case "$canonical_host_type" in + powerpc-apple-darwin*|*-sgi-*) + STRIP=: + ;; + *-cygwin-*|*-mingw-*) + MKOCTFILE="$MKOCTFILE -s" + ;; +esac + +dnl Things needed to link to X11 programs +dnl defines X_CFLAGS, X_LIBS +AC_SUBST(DEFHAVE_X) +AC_SUBST(X_LIBS) +AC_SUBST(X_CFLAGS) +AC_PATH_XTRA +if test "$no_x" = yes ; then + DEFHAVE_X= + XSTATUS="no (plot/g{input,text,zoom,rab} will not work)" +else + DEFHAVE_X="HAVE_X=1" + X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" + XSTATUS="yes" +fi + +OCTAVE_CHECK_EXIST(autoload,[ + HAVE_AUTOLOAD="yes" + OCTLINK=.octlink + MKOCTLINK=$TOPDIR/admin/octlink.sh +],[ + HAVE_AUTOLOAD="no" + OCTLINK=.oct + MKOCTLINK=$LN_S +]) +AC_SUBST(HAVE_AUTOLOAD) +AC_SUBST(OCTLINK) +AC_SUBST(MKOCTLINK) + +OCTAVE_CHECK_EXIST(do_fortran_indexing, + [HAVE_DO_FORTRAN_INDEXING="-DHAVE_DO_FORTRAN_INDEXING"],) +AC_SUBST(HAVE_DO_FORTRAN_INDEXING) + +OCTAVE_CHECK_EXIST(propagate_empty_matrices, + [PROPAGATE_EMPTY_MATRICES="-DHAVE_PROPAGATE_EMPTY_MATRICES"],) +AC_SUBST(HAVE_PROPAGATE_EMPTY_MATRICES) + +OCTAVE_CHECK_EXIST(ok_to_lose_imaginary_part, + [HAVE_OK_TO_LOSE_IMAGINARY_PART="-DHAVE_OK_TO_LOSE_IMAGINARY_PART"],) +AC_SUBST(HAVE_OK_TO_LOSE_IMAGINARY_PART) + +dnl Test for N-dimensional Arrays +TRY_MKOCTFILE([for N-dim arrays], +[#include <octave/dim-vector.h>], +[HAVE_ND_ARRAYS="-DHAVE_ND_ARRAYS"],) +AC_SUBST(HAVE_ND_ARRAYS) + +OCTAVE_CHECK_EXIST(class,[TYPEID_HAS_CLASS="-DTYPEID_HAS_CLASS"],) +AC_SUBST(TYPEID_HAS_CLASS) + +dnl Test for load/save functions in class +TRY_MKOCTFILE([for load/save functions in class], +[#include <octave/ov-scalar.h> +int main (void) { octave_scalar a; a.load_ascii(std::cin); }], +[CLASS_HAS_LOAD_SAVE="-DCLASS_HAS_LOAD_SAVE"],) +AC_SUBST(CLASS_HAS_LOAD_SAVE) + +TRY_MKOCTFILE([for Octave_map indexing], +[#include <octave/oct-map.h> +int main(void) { Octave_map a; a[["key"]]; }], +[HAVE_OCTAVE_MAP_INDEX="-DHAVE_OCTAVE_MAP_INDEX"],) +AC_SUBST(HAVE_OCTAVE_MAP_INDEX) + +TRY_MKOCTFILE([for old Octave concatenation], +[#include <octave/dNDArray.h> +int main(void) { NDArray a(dim_vector(1,1)); Array<int> idx(2,0); a=concat(a,a,idx); }], +[HAVE_OCTAVE_CONCAT="-DHAVE_OLD_OCTAVE_CONCAT"],) + +TRY_MKOCTFILE([for Octave concatenation], +[#include <octave/dNDArray.h> +int main(void) { NDArray a(dim_vector(1,1)); Array<int> idx(2,0); a=a.concat(a,idx); }], +[HAVE_OCTAVE_CONCAT="-DHAVE_OCTAVE_CONCAT"],) +AC_SUBST(HAVE_OCTAVE_CONCAT) + +TRY_MKOCTFILE([for swap_8_bytes], +[#include <sys/types.h> +#include <octave/config.h> +#include <octave/byte-swap.h> +int main(void) {long long a = 1; swap_8_bytes (&a,1);}],, +[HAVE_SWAP_BYTES="-DHAVE_SWAP_BYTES"]) +AC_SUBST(HAVE_SWAP_BYTES) + +TRY_MKOCTFILE([for op_uplus], +[#include <octave/config.h> +#include <octave/ov.h> +int main(void) {int i = octave_value::op_uplus;}], +[HAVE_OCTAVE_UPLUS="-DHAVE_OCTAVE_UPLUS"],) +AC_SUBST(HAVE_OCTAVE_UPLUS) + +dnl Test for the makeinfo program +AC_CHECK_PROG(MAKEINFO,makeinfo,makeinfo) +if [ test -n "$MAKEINFO" ]; then + dnl Check whether the makeinfo command accepts the + dnl "--no-split" option + touch conftest.texi + AC_MSG_CHECKING([for makeinfo --no-split]) + ac_try="$MAKEINFO --no-split conftest.texi" + if AC_TRY_EVAL(ac_try) ; then + MAKEINFO="$MAKEINFO --no-split" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + rm -f conftest.* +fi + +dnl Test for the texi2dvi program +AC_CHECK_PROG(TEXI2DVI,texi2dvi,texi2dvi) +if [ test -n "$TEXI2DVI" ]; then + dnl Check whether the texi2dvi command accepts the + dnl "--clean" option + cat > conftest.texi <<EOF +\input texinfo +@bye +EOF + AC_MSG_CHECKING([that texi2dvi runs]) + ac_try="$TEXI2DVI conftest.texi > /dev/null" + if AC_TRY_EVAL(ac_try) ; then + AC_MSG_RESULT(yes) + AC_MSG_CHECKING([for texi2dvi --clean]) + ac_try="$TEXI2DVI --clean conftest.texi > /dev/null" + if AC_TRY_EVAL(ac_try) ; then + TEXI2DVI="$TEXI2DVI --clean" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + else + TEXI2DVI="" + AC_MSG_RESULT(no) + fi + rm -f conftest.* +fi + +dnl Test for the texi2html program +AC_CHECK_PROG(TEXI2HTML,texi2html,texi2html) +if [ test -n "$TEXI2HTML" ]; then + STATUS="yes" + dnl Check whether the texi2html command accepts the + dnl "-split_chapter -number" option + touch conftest.texi + AC_MSG_CHECKING([for texi2html --clean]) + ac_try="$TEXI2HTML -split_chapter -number conftest.texi" + if AC_TRY_EVAL(ac_try) ; then + TEXI2HTML="$TEXI2HTML -split_chapter -number" + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + rm -f conftest.* + dnl TeTex 3.0 on Suse is leaving a conftest directory + rm -rf conftest +fi + +dnl Test for the dvipdf program +AC_CHECK_PROG(DVIPDF,dvipdf,dvipdf) + +dnl Test for the dvips program +AC_CHECK_PROG(DVIPS,dvips,dvips) + +MKDOC=$TOPDIR/admin/mkdoc +AC_SUBST(MKDOC) + +MKTEXI=$TOPDIR/admin/mktexi +AC_SUBST(MKTEXI) + +CONFIGURE_OUTPUTS="Makeconf octinst.sh" +STATUS_MSG=" +octave commands will install into the following directories: + m-files: $mpath + oct-files: $opath + binaries: $xpath +alternatives: + m-files: $altmpath + oct-files: $altopath + +shell commands will install into the following directories: + binaries: $bindir + man pages: $mandir + libraries: $libdir + headers: $includedir + +octave-forge is configured with + octave: $OCTAVE (version $OCTAVE_VERSION) + mkoctfile: $MKOCTFILE for Octave $subver + X11 support: $XSTATUS + makeinfo: $MAKEINFO + texi2dvi: $TEXI2DVI + texi2html: $TEXI2HTML + mkdoc: $MKDOC + mktexi: $MKTEXI + dvips: $DVIPS + dvipdf: $DVIPDF"
new file mode 100644 --- /dev/null +++ b/src/cordflt2.cc @@ -0,0 +1,214 @@ +// Copyright (C) 2000 Teemu Ikonen +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include <octave/oct.h> + +#ifdef HAVE_OCTAVE_20 +typedef Matrix boolMatrix; +#define bool_matrix_value matrix_value +#endif + +#define SWAP(a, b) { SWAP_temp = (a); (a)=(b); (b) = SWAP_temp; } + +// Template function for comparison +// ET is the type of the matrix element +template <class ET> +inline bool compare(const ET a, const ET b) +{ + if(a > b) + return 1; + else + return 0; +} + +// Explicit template function for complex compare +template <> inline bool compare<Complex>(const Complex a, const Complex b) +{ + double anorm2 = a.real() * a.real() + a.imag() * a.imag(); + double bnorm2 = b.real() * b.real() + b.imag() * b.imag(); + + if( anorm2 > bnorm2 ) { + return 1; + } else { + return 0; + } +} + +// select nth largest member from the array values +// Partitioning algorithm, see Numerical recipes chap. 8.5 +template <class ET> +ET selnth(ET *vals, int len, int nth) +{ + ET SWAP_temp; + ET hinge; + int l, r, mid, i, j; + + l = 0; + r = len - 1; + for(;;) { + // if partition size is 1 or two, then sort and return + if(r <= l+1) { + if(r == l+1 && compare<ET>(vals[l], vals[r])) { + SWAP(vals[l], vals[r]); + } + return vals[nth]; + } else { + mid = (l+r) >> 1; + SWAP(vals[mid], vals[l+1]); + // choose median of l, mid, r to be the hinge element + // and set up sentinels in the borders (order l, l+1 and r) + if(compare<ET>(vals[l], vals[r])) { + SWAP(vals[l], vals[r]); + } + if(compare<ET>(vals[l+1], vals[r])) { + SWAP(vals[l+1], vals[r]); + } + if(compare<ET>(vals[l], vals[l+1])) { + SWAP(vals[l], vals[l+1]); + } + i = l+1; + j = r; + hinge = vals[l+1]; + for(;;) { + do i++; while(compare<ET>(hinge, vals[i])); + do j--; while(compare<ET>(vals[j], hinge)); + if(i > j) + break; + SWAP(vals[i], vals[j]); + } + vals[l+1] = vals[j]; + vals[j] = hinge; + if(j >= nth) + r = j - 1; + if(j <= nth) + l = i; + } + } +} + +// Template function for doing the actual filtering +// MT is the type of the matrix to be filtered (Matrix or ComplexMatrix) +// ET is the type of the element of the matrix (double or Complex) +template <class MT, class ET> +octave_value_list do_filtering(MT A, int nth, boolMatrix dom, MT S) +{ + int i, j, c, d; + + int len = 0; + for(j = 0; j < dom.columns(); j++) { + for(i = 0; i < dom.rows(); i++) { + if(dom.elem(i,j)) + len++; + } + } + if(nth > len - 1) { + warning("nth should be less than number of non-zero values in domain"); + warning("setting nth to largest possible value\n"); + nth = len - 1; + } + if(nth < 0) { + warning("nth should be non-negative, setting to 1\n"); + nth = 0; // nth is a c-index + } + + int rowoffset = (dom.columns() + 1)/2 - 1; + int coloffset = (dom.rows() + 1)/2 - 1; + + //outputs + octave_value_list out; + const int origx = A.columns() - dom.columns()+1; + const int origy = A.rows() - dom.rows()+1; + MT retval = MT(origy, origx); + + int *offsets = new int[len]; + ET *values = new ET[len]; + ET *adds = new ET[len]; + + c = 0; + d = A.rows(); + for(j = 0; j < dom.columns(); j++) { + for(i = 0; i < dom.rows(); i++) { + if(dom.elem(i,j)) { + offsets[c] = (i - coloffset) + (j - rowoffset)*d; + adds[c] = S.elem(i,j); + c++; + } + } + } + + ET *data = A.fortran_vec(); + int base = coloffset + A.rows()*rowoffset; + for(j = 0; j < retval.columns(); j++) { + for(i = 0; i < retval.rows(); i++) { + for(c = 0; c < len; c++) { + values[c] = data[base + offsets[c]] + adds[c]; + } + base++; + retval(i, j) = selnth(values, len, nth); + } + base += dom.rows() - 1; + } + + out(0) = octave_value(retval); + + return out; +} + +// instantiate template functions +template bool compare<double>(const double, const double); +template double selnth(double *, int, int); +template Complex selnth(Complex *, int, int); +template octave_value_list do_filtering<Matrix, double>(Matrix, int, boolMatrix, Matrix); +// g++ is broken, explicit instantiation of specialized template function +// confuses the compiler. +//template int compare<Complex>(const Complex, const Complex); +template octave_value_list do_filtering<ComplexMatrix, Complex>(ComplexMatrix, int, boolMatrix, ComplexMatrix); + +DEFUN_DLD(cordflt2, args, , +"function retval = cordflt2(A, nth, domain, S)\n\ +\n\ + Implementation of two-dimensional ordered filtering. User interface\n\ + in ordfilt2.m") +{ + if(args.length() != 4) { + print_usage (); + return octave_value_list(); + } + + // nth is an index to an array, thus - 1 + int nth = (int) (args(1).vector_value())(0) - 1; + boolMatrix dom = args(2).bool_matrix_value(); + + octave_value_list retval; + + if(args(0).is_real_matrix()) { + Matrix A = args(0).matrix_value(); + Matrix S = args(3).matrix_value(); + retval = do_filtering<Matrix, double>(A, nth, dom, S); + } + else if(args(0).is_complex_matrix()) { + ComplexMatrix A = args(0).complex_matrix_value(); + ComplexMatrix S = args(3).complex_matrix_value(); + retval = do_filtering<ComplexMatrix, Complex>(A, nth, dom, S); + } + else { + error("A should be real or complex matrix\n"); + return octave_value_list(); + } + + return retval; + +}
new file mode 100644 --- /dev/null +++ b/src/graycomatrix.cc @@ -0,0 +1,148 @@ +/* Copyright (C) 2004 Stefan van der Walt <stefan@sun.ac.za> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <octave/oct.h> + +DEFUN_DLD(graycomatrix, args, , "\ +\ +usage: P = graycomatrix(I, levels, distances, angles)\n\ +\n\ + Calculate the gray-level co-occurrence matrix P = f(i,j,d,theta)\n\ + of a gray-level image.\n\ +\n\ + P is a 4-dimensional matrix (histogram). The value P(i,j,d,theta)\n\ + is the number of times that gray-level j occurs at a distance 'd' and\n\ + at an angle 'theta' from gray-level j.\n\ +\n\ + 'I' is the input image which should contain integers in [0, levels-1],\n\ + where 'levels' indicate the number of gray-levels counted (typically\n\ + 256 for an 8-bit image). 'distances' and 'angles' are vectors of\n\ + the different distances and angles to use.\n" ) { + + // 4-dimensional histogram + // P = f(i, j, d, theta) where i and j are gray levels + // See Pattern Recognition Engineering (Morton Nadler & Eric P. Smith) + + octave_value_list retval; + + if (args.length() != 4) { + print_usage (); + // 'I' must be integer values [0, nr_of_levels-1] + + return retval; + } + + // Input arguments + Matrix I = args(0).matrix_value(); + int L = args(1).int_value(); + ColumnVector d = ColumnVector(args(2).vector_value()); + ColumnVector th = ColumnVector(args(3).vector_value()); + + if (error_state) { + print_usage (); + return retval; + } + + // Create output NDArray, P + dim_vector dim = dim_vector(); + dim.resize(4); + dim(0) = L; dim(1) = L; dim(2) = d.length(); dim(3) = th.length(); + NDArray P = NDArray(dim, 0); + + // Run through image + int d_max = (int)ceil(d.max()); + int cnt = 0; + + for (int r = 0; r < I.rows(); r++) { + for (int c = 0; c < I.columns(); c++) { + int i = (int)I(r,c); + + for (int d_idx = 0; d_idx < d.length(); d_idx++) { + int d_val = (int)d(d_idx); + for (int th_idx = 0; th_idx < th.length(); th_idx++) { + + double angle = th(th_idx); + + int row = r + (int)floor(cos(angle) * d_val + 0.5); + int col = c - (int)floor(sin(angle) * d_val + 0.5); + + if ( ( row >= 0 ) && ( row < I.rows() ) && + ( col >= 0 ) && ( col < I.cols() ) ) { + + int j = (int)I(row, col); + + if (i >= 0 && i < L && j >= 0 && j < L) { + Array<int> coord = Array<int> (4); + coord(0) = i; + coord(1) = j; + coord(2) = d_idx; + coord(3) = th_idx; + + P(coord)++; + } else { + warning("Image contains invalid gray-level! (%d, %d)", i, j); + } + } + + } + } + + } + } + + return octave_value(P); + +} + +/* + +%!shared a +%!test +%! a = [0 0 0 1 2; +%! 1 1 0 1 1; +%! 2 2 1 0 0; +%! 1 1 0 2 0; +%! 0 0 1 0 1]; +%! squeeze(graycomatrix(a, 3, 1, -pi/4)) == [4 2 0; +%! 2 3 2; +%! 1 2 0]; +%! +%!assert(size(graycomatrix(a, 3, 1:5, [0:3]*-pi/4)), [3, 3, 5, 4]) + +%!demo +%! +%! # Pattern Recognition Engineering (Nadler & Smith) +%! # Digital Image Processing (Gonzales & Woods), p. 668 +%! +%! a = [0 0 0 1 2; +%! 1 1 0 1 1; +%! 2 2 1 0 0; +%! 1 1 0 2 0; +%! 0 0 1 0 1]; +%! +%! graycomatrix(a, 3, 1, [0 1]*-pi/4) +%! + + +*/
new file mode 100644 --- /dev/null +++ b/src/houghtf.cc @@ -0,0 +1,129 @@ +/* Copyright (C) 2004 Stefan van der Walt <stefan@sun.ac.za> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <octave/oct.h> + +DEFUN_DLD(houghtf, args, , "\ +\ +usage: [H, R] = houghtf(I[, angles])\n\ +\n\ + Calculate the straight line Hough transform of an image.\n\ +\n\ + The image, I, should be a binary image in [0,1]. The angles are given\n\ + in degrees and defaults to -90..90.\n\ +\n\ + H is the resulting transform, R the radial distances.\n\ +\n\ + See also: Digital Image Processing by Gonzales & Woods (2nd ed., p. 587)\n") { + + octave_value_list retval; + bool DEF_THETA = false; + + if (args.length() == 1) { + DEF_THETA = true; + } else if (args.length() != 2) { + print_usage (); + return retval; + } + + Matrix I = args(0).matrix_value(); + + ColumnVector thetas = ColumnVector(); + if (!DEF_THETA) { + thetas = ColumnVector(args(1).vector_value()); + } else { + thetas = ColumnVector(Range(-90,90).matrix_value()); + } + + if (error_state) { + print_usage (); + return retval; + } + + thetas = thetas / 180 * M_PI; + + int r = I.rows(); + int c = I.columns(); + + Matrix xMesh = Matrix(r, c); + Matrix yMesh = Matrix(r, c); + for (int m = 0; m < r; m++) { + for (int n = 0; n < c; n++) { + xMesh(m, n) = n+1; + yMesh(m, n) = m+1; + } + } + + Matrix size = Matrix(1, 2); + size(0) = r; size(1) = c; + double diag_length = sqrt( size.sumsq()(0) ); + int nr_bins = 2 * (int)ceil(diag_length) - 1; + RowVector bins = RowVector( Range(1, nr_bins).matrix_value() ) - ceil(nr_bins/2.); + + Matrix J = Matrix(bins.length(), 0); + + for (int i = 0; i < thetas.length(); i++) { + double theta = thetas(i); + ColumnVector rho_count = ColumnVector(bins.length(), 0); + + double cT = cos(theta); double sT = sin(theta); + for (int x = 0; x < r; x++) { + for (int y = 0; y < c; y++) { + if ( I(x, y) == 1 ) { + int rho = (int)floor( cT*x + sT*y + 0.5 ); + int bin = (int)(rho - bins(0)); + if ( (bin > 0) && (bin < bins.length()) ) { + rho_count( bin )++; + } + } + } + } + + J = J.append( rho_count ); + } + + retval.append(J); + retval.append(bins); + return retval; + +} + +/* +%!test +%! I = zeros(100, 100); +%! I(1,1) = 1; I(100,100) = 1; I(1,100) = 1; I(100, 1) = 1; I(50,50) = 1; +%! [J, R] = houghtf(I); J = J / max(J(:)); +%! assert(size(J) == [length(R) 181]); +%! + +%!demo +%! I = zeros(100, 150); +%! I(30,:) = 1; I(:, 65) = 1; I(35:45, 35:50) = 1; +%! for i = 1:90, I(i,i) = 1;endfor +%! I = imnoise(I, 'salt & pepper'); +%! imshow(I); +%! J = houghtf(I); J = J / max(J(:)); +%! imshow(J, bone(128), 'truesize'); + +*/
new file mode 100755 --- /dev/null +++ b/src/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0
new file mode 100644 --- /dev/null +++ b/src/jpgread.cc @@ -0,0 +1,181 @@ + // + // This is a hack into octave + // based on jpgread.c by jpgread by Drea Thomas, The Mathworks and the + // examples in the IJG distribution. + // + // (C) 1998 Andy Adler. This code is in the public domain + // USE THIS CODE AT YOUR OWN RISK + // + // $Id$ + // + +/* Modified: Stefan van der Walt <stefan@sun.ac.za> + * Date: 27 January 2004 + * - Manual error handler to prevent segfaults in Octave. + * - Use uint8NDArray for output. + */ + +/* + * Compilation: + * First, try + * mkoctfile jpgread.cc -ljpeg + * + * If this doesn't work, install the jpeg library which is part of + * "The Independent JPEG Group's JPEG software" collection. + * + * The jpeg library came from + * + * ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6.tar.gz + * + * Extract and build the library: + * tar xvfz jpegsrc.v6.tar.gz + * cd jpeg-6b + * ./configure + * make + * make test + * + * Compile this file using: + * mkoctfile jpgread.cc -I<jpeg-6b include dir> -L<jpeg-6b lib dir> -ljpeg + */ + +#include <octave/oct.h> +#include <iostream> +#include <csetjmp> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "jpeglib.h" + +#ifdef __cplusplus +} //extern "C" +#endif + +struct oct_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct oct_error_mgr * oct_error_ptr; + +METHODDEF(void) +oct_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to an oct_error_mgr struct, so coerce pointer */ + oct_error_ptr octerr = (oct_error_ptr) cinfo->err; + + /* Format error message and send to interpreter */ + char errmsg[JMSG_LENGTH_MAX]; + (octerr->pub.format_message)(cinfo, errmsg); + error("jpgread: %s", errmsg); + + /* Return control to the setjmp point */ + longjmp(octerr->setjmp_buffer, 1); +} + +DEFUN_DLD (jpgread, args, nargout , +"usage: I = jpgread('filename')\n\ +\n\ + Read a JPEG file from disk.\n\ +\n\ + For a grey-level image, the output is an MxN matrix. For a\n\ + colour image, three such matrices are returned (MxNx3),\n\ + representing the red, green and blue components. The output\n\ + is of class 'uint8'.\n\ +\n\ + See also: imread, im2double, im2gray, im2rgb.") +{ + octave_value_list retval; + int nargin = args.length(); + + FILE * infile; + + JSAMPARRAY buffer; + long row_stride; + struct jpeg_decompress_struct cinfo; + struct oct_error_mgr jerr; + + // + // We bail out if the input parameters are bad + // + if ((nargin != 1) || !args(0).is_string() || (nargout != 1)) { + print_usage (); + return retval; + } + + // + // Open jpg file + // + std::string filename = args(0).string_value(); + if ((infile = fopen(filename.c_str(), "rb")) == NULL) { + error("jpgread: couldn't open file %s", filename.c_str()); + return retval; + } + + // + // Initialize the jpeg library + // + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = oct_error_exit; + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + jpeg_destroy_decompress(&cinfo); + fclose(infile); + return retval; + } + + jpeg_create_decompress(&cinfo); + + // + // Read the jpg header to get info about size and color depth + // + jpeg_stdio_src(&cinfo, infile); + jpeg_read_header(&cinfo, TRUE); + jpeg_start_decompress(&cinfo); + + // + // Allocate buffer for one scan line + // + row_stride = cinfo.output_width * cinfo.output_components; + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + // + // Create an NDArray for the output. Loop through each of the + // scanlines and copy the image data from the buffer. + // + + dim_vector dim = dim_vector(); + dim.resize(3); + dim(0) = cinfo.output_height; + dim(1) = cinfo.output_width; + dim(2) = cinfo.output_components; + uint8NDArray out = uint8NDArray(dim, 0); + + Array<int> coord = Array<int> (3); + for (unsigned long j=0; cinfo.output_scanline < cinfo.output_height; j++) { + jpeg_read_scanlines(&cinfo, buffer, 1); + + coord(0) = j; + for (unsigned long i=0; i<cinfo.output_width; i++) { + coord(1) = i; + for (unsigned int c = 0; c < cinfo.output_components; c++) { + coord(2) = c; + out(coord) = buffer[0][i*cinfo.output_components+c]; + } + } + } + retval.append(out.squeeze()); + + // + // Clean up + // + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(infile); + + return retval; +}
new file mode 100644 --- /dev/null +++ b/src/jpgwrite.cc @@ -0,0 +1,221 @@ + // This is a hack into octave + // based on jpgwrite.c by jpgread by Drea Thomas, The Mathworks, and the + // examples in the IJG distribution. + // + // (C) 1998 Andy Adler. This code is in the public domain + // USE THIS CODE AT YOUR OWN RISK + // + // $Id$ + // + +#include <octave/oct.h> +#include <iostream> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "jpeglib.h" + +#ifdef __cplusplus +} //extern "C" +#endif + +#define GRAYIMAGES + +/* + * Simple jpeg writing MEX-file. + * + * Synopsis: + * jpgwrite(filename,r,g,b,quality) + * + * Compilation: + * First, try + * mkoctfile jpgwrite.cc -ljpeg + * + * If this doesn't work, then do + * + * Calls the jpeg library which is part of + * "The Independent JPEG Group's JPEG software" collection. + * + * The jpeg library came from, + * + * ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6.tar.gz + */ + +DEFUN_DLD (jpgwrite, args, , +"JPGWRITE Write a JPEG file to disk.\n\ + jpgwrite('filename',R,G,B,quality) writes the specified file\n\ + using the Red, Green, and Blue intensity matrices, at the given quality.\n\ + \n\ + jpgwrite('filename',M,quality) writes a grey-scale image.\n\ + \n\ + Data must be [0 255] or the high bytes will be lost\n\ + \n\ + If specified, quality should be in the range 1-100 and will default to \n\ + 75 if not specified. 100 is best quality, 1 is best compression.\n\ + \n\ + See also JPGREAD") +{ + octave_value_list retval; + int nargin = args.length(); + + FILE * outfile; + + JSAMPARRAY buffer; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + int quality=75; //default value + +// +// We bail out if the input parameters are bad +// + if (nargin < 2 || !args(0).is_string() ) { + print_usage (); + return retval; + } + + +// +// Open jpg file +// + std::string filename = args(0).string_value(); + if ((outfile = fopen(filename.c_str(), "wb")) == NULL) { + error("Couldn't open file"); + return retval; + } + +// +// Set Jpeg parameters +// + if (nargin == 3) { + quality= (int) args(2).double_value(); + } else if (nargin == 5) { + quality= (int) args(4).double_value(); + } + +// +// Initialize the jpeg library +// Read the jpg header to get info about size and color depth +// + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, outfile); + + +// +// set parameters for compression +// + + if ( nargin <= 3 ) { +// +// we're here because only one matrix of grey scale values was provided +// + Matrix avg= args(1).matrix_value(); + long image_width = args(1).columns(); + long image_height = args(1).rows(); + + + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; +#ifdef GRAYIMAGES + cinfo.input_components = 1; + cinfo.input_components = JCS_GRAYSCALE; +#else + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; +#endif + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); +// +// start compressor +// + jpeg_start_compress(&cinfo, TRUE); + +// +// Allocate buffer for one scan line +// + long row_stride = image_width * cinfo.input_components ; + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); +// +// Now, loop thru each of the scanlines. For each, copy the image +// data from the buffer, data must be [0 255] +// + for( long j=0; cinfo.next_scanline < cinfo.image_height; j++) { + for(unsigned long i=0; i<cinfo.image_width; i++) { +#ifdef GRAYIMAGES + buffer[0][i] = (unsigned char) avg(j,i); +#else + buffer[0][i*3+0] = (unsigned char) avg(j,i); + buffer[0][i*3+1] = (unsigned char) avg(j,i); + buffer[0][i*3+2] = (unsigned char) avg(j,i); +#endif + } + jpeg_write_scanlines(&cinfo, buffer,1); + } + + } // if nargin <= 3 + else { +// +// we're here because red green and blue matrices were provided +// we assume that they're the same size +// + Matrix red = args(1).matrix_value(); + Matrix green= args(2).matrix_value(); + Matrix blue = args(3).matrix_value(); + long image_width = args(1).columns(); + long image_height = args(1).rows(); + + if ( args(2).columns() != image_width || + args(3).columns() != image_width || + args(2).rows() != image_height || + args(3).rows() != image_height ) { + error("R,G,B matrix sizes aren't the same"); + return retval; + } + + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE ); +// +// start compressor +// + jpeg_start_compress(&cinfo, TRUE); + +// +// Allocate buffer for one scan line +// + long row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); +// +// Now, loop thru each of the scanlines. For each, copy the image +// data from the buffer, data must be [0 255] +// + for( long j=0; cinfo.next_scanline < cinfo.image_height; j++) { + for(unsigned long i=0; i<cinfo.image_width; i++) { + buffer[0][i*3+0] = (unsigned char) red(j,i); + buffer[0][i*3+1] = (unsigned char) green(j,i); + buffer[0][i*3+2] = (unsigned char) blue(j,i); + } + jpeg_write_scanlines(&cinfo, buffer,1); + } + + } // else nargin > 3 + +// +// Clean up +// + + jpeg_finish_compress(&cinfo); + fclose(outfile); + jpeg_destroy_compress(&cinfo); + + + return retval; + +}
new file mode 100755 --- /dev/null +++ b/src/octinst.sh.in @@ -0,0 +1,93 @@ +#! /bin/sh + +# octinst.sh source mpath opath xpath [altmpath altopath] + +# Copies all m-files and oct-files from the source directory to the +# mpath and opath respectively. Preserves links. Files in +# source/data are copied to mpath. Files in the source/bin are copied +# to xpath. m-files and oct-files in source/alternatives are copied to +# altmpath and altopath respectively + +if test $# -lt 4 ; then + echo 'Not enough arguments' + exit 1 +fi + +# interpret input parameters +source=$1; shift +mpath=$1; shift +opath=$1; shift +xpath=$1; shift +if test $# -ge 1; then altmpath=$1; shift; fi +if test $# -ge 1; then altopath=$1; shift; fi +INSTALL="@INSTALL@" +INSTALL_DATA="@INSTALL_DATA@" +INSTALL_PROGRAM="@INSTALL_PROGRAM@" +INSTALL_SCRIPT="@INSTALL_SCRIPT@" +MKPKGADD="@TOPDIR@/admin/mkpkgadd" +COPY_FLAGS="@COPY_FLAGS@" + +# grab the m-files +files=`echo $source/*.m` +if test "$files" != "$source/*.m" ; then + $INSTALL -d $mpath + $INSTALL_DATA $files $mpath +fi + +# grab the oct-files +files=`echo $source/*.oct` +if test "$files" != "$source/*.oct" ; then + $INSTALL -d $opath +## Grrr... install doesn't preserve links. Hope this works. + cp $COPY_FLAGS $files $opath +fi + +# install alternatives +if test -d "$source/alternatives" ; then + # m-files + files=`echo $source/alternatives/*.m` + if test "$files" != "$source/alternatives/*.m" ; then + $INSTALL -d $altmpath + $INSTALL_DATA $files $altmpath + fi + # oct-files + files=`echo $source/alternatives/*.oct` + if test "$files" != "$source/alternatives/*.oct" ; then + $INSTALL -d $altopath + $INSTALL_DATA $files $altopath + fi +fi + +# Create PKG_ADD, and destroy it immediately if it is empty +# XXX FIXME XXX no PKG_ADD created if only oct-files and no m-files. +if test -d "$mpath" ; then + $MKPKGADD $source > $mpath/PKG_ADD + if test -z "`cat $mpath/PKG_ADD`" ; then rm -f $mpath/PKG_ADD; fi +fi +# PKG_ADD for alternatives +if test -d "$source/alternatives" -a -d "$altmpath" ; then + $MKPKGADD $source/alternatives > $altmpath/PKG_ADD + if test -z "`cat $altmpath/PKG_ADD`" ; then rm $altmpath/PKG_ADD; fi +fi + +# grab the data files, skipping the CVS directory +files=`echo $source/data/* | sed -e "s/[^ ]*CVS//"` +if test -n "$files" -a "$files" != "$source/data/*" ; then + $INSTALL -d $mpath + $INSTALL_DATA $files $mpath +fi + +# grab the executable files, skipping the CVS directory +files=`echo $source/bin/* | sed -e "s/[^ ]*CVS//"` +if test -n "$files" -a "$files" != "$source/bin/*" ; then + $INSTALL -d $xpath + $INSTALL_PROGRAM $files $xpath +fi + +# grab the script files, skipping the CVS directory +files=`echo $source/scripts/* | sed -e "s/[^ ]*CVS//"` +if test -n "$files" -a "$files" != "$source/scripts/*" ; then + $INSTALL -d $xpath + $INSTALL_SCRIPT $files $xpath +fi +
new file mode 100644 --- /dev/null +++ b/src/pngcanvas.h @@ -0,0 +1,76 @@ +/* + * readpng.h + * + * Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Modified: Stefan van der Walt <stefan@sun.ac.za> + * Date: 28 January 2005 + * - Fix bugs, restructure + */ + +typedef struct +{ + int width; + int height; + int bit_depth; + int color_type; + unsigned char **row_pointers; +} canvas; + +//////////////Libcanvas/////////// +canvas *new_canvas(int width, int height, int stride) +{ + // Default stride if none given + if (stride==0) stride=width*4; + + // Clean allocation of canvas structure + canvas *can=new(canvas); + unsigned char *image_data = new unsigned char[stride*height]; + unsigned char **row_pointers = new unsigned char *[height]; + if (can == NULL || image_data == NULL || row_pointers == NULL) + { + if (can == NULL) delete can; + if (image_data == NULL) delete[] image_data; + if (row_pointers == NULL) delete[] row_pointers; + return NULL; + } + + // Fill in canvas structure + can->width=width; + can->height=height; + can->bit_depth=8; + can->color_type=PNG_COLOR_TYPE_RGB_ALPHA; + can->row_pointers = row_pointers; + for (int i=0; i < height; i++) row_pointers[i] = image_data + i*stride; + + return can; +} + +void delete_canvas(canvas *can) +{ + + if (can!=NULL) + { + delete[] can->row_pointers[0]; + delete[] can->row_pointers; + delete can; + } + return; +} +
new file mode 100644 --- /dev/null +++ b/src/pngread.cc @@ -0,0 +1,239 @@ +/* + * pngread.cc + * + * Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + +Load PNG files to octave using libpng; + + PNG (Portable Network Graphics) is an extensible file format for the + lossless, portable, well-compressed storage of raster images. PNG pro- + vides a patent-free replacement for GIF and can also replace many com- + mon uses of TIFF. Indexed-color, grayscale, and truecolor images are + supported, plus an optional alpha channel. Sample depths range from 1 + to 16 bits. + +*/ + +/* + * Modified: Stefan van der Walt <stefan@sun.ac.za> + * Date: 28 January 2005 + * - Fix bugs, restructure + */ + +#include "png.h" +#include "pngcanvas.h" +#include <octave/oct.h> + +canvas *load_canvas(char *filename); + +DEFUN_DLD (pngread, args, nargout , +"-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {[@var{I}, @var{alpha}] =} pngread(@var{filename})\n\ +\n\ +Read a PNG file from disk.\n\ +\n\ +The image is returned as a matrix of dimension MxN (for grey-level images)\n\ +or MxNx3 (for colour images). The numeric type of @var{I} and @var{alpha}\n\ +is @code{uint8} for grey-level and RGB images, or @code{logical} for\n\ +black-and-white images.\n\ +\n\ +@end deftypefn\n\ +@seealso{imread}") +{ + octave_value_list retval; + int nargin = args.length(); + + // + // We bail out if the input parameters are bad + // + if (nargin != 1 || !args(0).is_string()) { + print_usage (); + return retval; + } + + // + // Load png file + // + canvas *pic=load_canvas((char *)args(0).string_value().c_str()); + if (!pic) return retval; + + dim_vector dim = dim_vector(); + dim.resize(3); + dim(0) = pic->height; + dim(1) = pic->width; + dim(2) = 3; + + if ( (pic->color_type == PNG_COLOR_TYPE_GRAY) || + (pic->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || + ((pic->color_type == PNG_COLOR_TYPE_PALETTE) && (pic->bit_depth == 1)) ) + dim(2) = 1; + + if (pic->bit_depth > 1 && pic->bit_depth < 8) + pic->bit_depth = 8; + + NDArray out(dim); + + dim.resize(2); + NDArray alpha(dim); + + Array<int> coord = Array<int> (3); + + for (unsigned long j=0; j < pic->height; j++) { + coord(0) = j; + for (unsigned long i=0; i < pic->width; i++) { + coord(1) = i; + + for (int c = 0; c < out.dims()(2); c++) { + coord(2) = c; + out(coord) = pic->row_pointers[j][i*4+c]; + } + alpha(j,i) = pic->row_pointers[j][i*4+3]; + } + } + out = out.squeeze(); + + switch (pic->bit_depth) { + case 1: + retval.append((boolNDArray)out); + retval.append((boolNDArray)alpha); + break; + case 8: + retval.append((uint8NDArray)out); + retval.append((uint8NDArray)alpha); + break; + case 16: + retval.append((uint16NDArray)out); + retval.append((uint16NDArray)alpha); + break; + default: + retval.append(out); + retval.append(alpha); + } + + delete_canvas(pic); + return retval; +} + +canvas *load_canvas(char *filename) +{ + png_structp png_ptr; + png_infop info_ptr; + + FILE *infile = fopen(filename,"r"); + if (!infile) { + error("pngread could not open file %s", filename); + return NULL; + } + + unsigned char sig[8]; + fread(sig,1,8,infile); + if (!png_check_sig(sig,8)) { + error("pngread invalid signature in %s", filename); + fclose(infile); + return NULL; + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); + if (!png_ptr) { + error("pngread out of memory"); + fclose(infile); + return NULL; + } + + info_ptr = png_create_info_struct(png_ptr); + if(!info_ptr) { + error("pngread can't generate info"); + png_destroy_read_struct(&png_ptr,NULL,NULL); + fclose(infile); + return NULL; + } + + /* Set error handling */ + if (setjmp(png_jmpbuf(png_ptr))) { + error("pngread: libpng exited abnormally"); + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + fclose(infile); + return NULL; + } + + png_init_io(png_ptr, infile); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + + png_uint_32 width,height; + int color_type, bit_depth; + png_get_IHDR(png_ptr,info_ptr,&width,&height, + &bit_depth,&color_type,NULL,NULL,NULL); + + /* Transform grayscale images with depths < 8-bit to 8-bit, change + * paletted images to RGB, and add a full alpha channel if there is + * transparency information in a tRNS chunk. + */ + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png_ptr); + } + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { + png_set_gray_1_2_4_to_8(png_ptr); + } + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { //add alpha + png_set_tRNS_to_alpha(png_ptr); + } + + // Always transform image to RGB + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + // If no alpha layer is present, create one + if (color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_RGB) + png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); + + if (bit_depth < 8) { + png_set_packing(png_ptr); + } + + // For now, use 8-bit only + if (bit_depth == 16) { + png_set_strip_16(png_ptr); + } + + png_read_update_info(png_ptr,info_ptr); + + // Read the data from the file + int stride = png_get_rowbytes(png_ptr, info_ptr); + canvas *can = new_canvas(width, height, stride); + + if (can) { + png_read_image(png_ptr, can->row_pointers); + } else { + error("pngread out of memory"); + } + + png_read_end(png_ptr,NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + fclose(infile); + + // Set color type and depth. Used to determine octave output arguments. + can->color_type = color_type; + can->bit_depth = bit_depth; + return can; +}
new file mode 100644 --- /dev/null +++ b/src/pngwrite.cc @@ -0,0 +1,166 @@ +/* + * pngwrite.cc + * + * Copyright (C) 2003 Nadav Rotem <nadav256@hotmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + +Write PNG files to disk from octave + + PNG (Portable Network Graphics) is an extensible file format for the + lossless, portable, well-compressed storage of raster images. PNG pro- + vides a patent-free replacement for GIF and can also replace many com- + mon uses of TIFF. Indexed-color, grayscale, and truecolor images are + supported, plus an optional alpha channel. Sample depths range from 1 + to 16 bits. + +*/ + +/* + * Modified: Stefan van der Walt <stefan@sun.ac.za> + * Date: 28 January 2005 + * - Fix bugs, restructure + */ + +#include "png.h" +#include "pngcanvas.h" +#include <octave/oct.h> + +void save_canvas(canvas *can, char *filename); + +DEFUN_DLD (pngwrite, args, ,"\ +pngwrite writes a png file to the disk.\n\ + pngwrite('filename',R,G,B,A) writes the specified file\n\ + using the Red, Green, Blue and Alpha matrices.\n\ + \n\ + Data must be [0 255] or the high bytes will be lost.") +{ + octave_value_list retval; + int nargin = args.length(); + + // + // We bail out if the input parameters are bad + // + if (nargin < 5 || !args(0).is_string() ) { + print_usage (); + return retval; + } + + Matrix red = args(1).matrix_value(); + Matrix green= args(2).matrix_value(); + Matrix blue = args(3).matrix_value(); + Matrix alpha= args(4).matrix_value(); + + long image_width = args(1).columns(); + long image_height = args(1).rows(); + + if ( args(2).columns() != image_width || + args(3).columns() != image_width || + args(4).columns() != image_width || + args(2).rows() != image_height || + args(3).rows() != image_height || + args(4).rows() != image_height ) + { + error("pngwrite R,G,B,A matrix sizes aren't the same"); + return retval; + } + + canvas *pic=new_canvas(image_width, image_height, image_width*4); + if (!pic) { + error("pngwrite out of memory"); + return retval; + } + + for(int i=0; i < pic->width; i++) { + for(int j=0; j < pic->height; j++) { + pic->row_pointers[j][i*4+0]=(unsigned char)(red(j,i)); + pic->row_pointers[j][i*4+1]=(unsigned char)(green(j,i)); + pic->row_pointers[j][i*4+2]=(unsigned char)(blue(j,i)); + pic->row_pointers[j][i*4+3]=(unsigned char)(alpha(j,i)); + } + } + + + save_canvas(pic,(char *)args(0).string_value().c_str()); + delete_canvas(pic); + + return retval; +} + +void save_canvas(canvas *can,char *filename) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + + fp = fopen(filename, "wb"); + if (fp == NULL) { + error("pngwrite could not open %s", filename); + return; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) { + fclose(fp); + error("pngwrite: cannot create write structure"); + return; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + fclose(fp); + error("pngwrite: cannot not create image structure"); + png_destroy_write_struct(&png_ptr, png_infopp_NULL); + return; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + fclose(fp); + png_destroy_write_struct(&png_ptr, &info_ptr); + error("pngread: libpng exited abnormally"); + return; + } + + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr, 3); + + png_set_IHDR(png_ptr, info_ptr, can->width, can->height, + can->bit_depth, can->color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + + png_set_gAMA(png_ptr, info_ptr, 0.7); + + time_t gmt; + png_time mod_time; + png_text text_ptr[2]; + time(&gmt); + png_convert_from_time_t(&mod_time, gmt); + png_set_tIME(png_ptr, info_ptr, &mod_time); + text_ptr[0].key = "Created by"; + text_ptr[0].text = "Octave"; + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + + png_set_text(png_ptr, info_ptr, text_ptr, 1); + + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, can->row_pointers); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); +}
new file mode 100644 --- /dev/null +++ b/src/rotate_scale.cc @@ -0,0 +1,179 @@ +/* + * ROTATE_SCALE: rotate and scale a matrix using bilinear interpolation + * imo= block(im, xregs, yregs); + * + * Copyright (C) 2003 Andy Adler + * This code has no warrany whatsoever. + * Do what you like with this code as long as you + * leave this copyright in place. + * + * $Id$ + */ + +#include <octave/oct.h> + +void +calc_rotation_params( + double x0l,double y0l,double x0r,double y0r, + double x1l,double y1l,double x1r,double y1r, + double* Tx_x, double* Ty_x, + double* Tx_y, double* Ty_y, + double* Tx_1, double* Ty_1 ); +void +do_interpolation ( + double Tx_x, double Ty_x, + double Tx_y, double Ty_y, + double Tx_1, double Ty_1, + int x0max, int y0max,// initial size + int x1max, int y1max,// output size + const double * img0, + double * img1 ); + +DEFUN_DLD (rotate_scale, args, , + "ROTATE_SCALE: arbitrary rotation and scaling of an image\n" + " using fast bilinear interpolation\n" + "im1 = rotate_scale(im0, lm0, lm1, out_size)\n" + " where:\n" + "im0 = input image\n" + "lm0 = landmarks of points in original image [ x1,x2;y1,y2 ]\n" + "im1 = output image, where size(im1) == out_size\n" + "lm1 = landmarks of points in output image [ x1,x2;y1,y2 ]\n" + "\n" + " note1: two landmarks must be specified for lm0 and lm1\n" + " note2: all images have a single component\n" + " to use this for colour images, use:\n" + " r_im1= rotate_scale( red_im0, lm0, lm1, out_size)\n" + " g_im1= rotate_scale( grn_im0, lm0, lm1, out_size)\n" + " b_im1= rotate_scale( blu_im0, lm0, lm1, out_size)\n" + "\n" + " example:\n" + " im0= zeros(100); im0(25:75,25:75)=1;\n" + " im1= rotate_scale( im0, [40,60;50,50],[60,90;60,90],[120,120]);\n" +) +{ + octave_value_list retval; + if (args.length() < 4 || + !args(0).is_matrix_type() || + !args(1).is_matrix_type() || + !args(2).is_matrix_type() || + !args(3).is_matrix_type() + ) { + print_usage (); + return retval; + } + + Matrix im0( args(0).matrix_value() ); + const double * im0p = im0.data(); + Matrix lm0( args(1).matrix_value() ); + Matrix lm1( args(2).matrix_value() ); + ColumnVector out_size( args(3).vector_value() ); + + int inp_hig= im0.rows(); + int inp_wid= im0.cols(); + + int out_hig= (int) out_size(0); + int out_wid= (int) out_size(1); + Matrix im1( out_hig, out_wid); + double * im1p = im1.fortran_vec(); + + double Tx_x; double Ty_x; + double Tx_y; double Ty_y; + double Tx_1; double Ty_1; + calc_rotation_params( + lm0(0,0), lm0(1,0), lm0(0,1), lm0(1,1), + lm1(0,0), lm1(1,0), lm1(0,1), lm1(1,1), + & Tx_x, & Ty_x, + & Tx_y, & Ty_y, + & Tx_1, & Ty_1 ); + + do_interpolation( Tx_x, Ty_x, Tx_y, Ty_y, Tx_1, Ty_1, + inp_wid, inp_hig, out_wid, out_hig, + im0p, im1p ); + + retval(0) = im1; + return retval; +} + +inline double sqr(double a) { return (a)*(a); } + +void +calc_rotation_params( + double x1l,double y1l,double x1r,double y1r, + double x0l,double y0l,double x0r,double y0r, + double* Tx_x, double* Ty_x, + double* Tx_y, double* Ty_y, + double* Tx_1, double* Ty_1 + ) +{ + double d0= sqrt( sqr(x0l-x0r) + sqr(y0l-y0r) ); + double d1= sqrt( sqr(x1l-x1r) + sqr(y1l-y1r) ); + double dr= d1/d0; + + double a0= atan2( y0l-y0r , x0l-x0r ); + double a1= atan2( y1l-y1r , x1l-x1r ); + double ad= a1-a0; + double dr_cos_ad= dr*cos(ad); + double dr_sin_ad= dr*sin(ad); + + double x0m= (x0l+x0r)/2; + double y0m= (y0l+y0r)/2; + double x1m= (x1l+x1r)/2; + double y1m= (y1l+y1r)/2; + + *Tx_x= dr_cos_ad; + *Ty_x= dr_sin_ad; + *Tx_y= -dr_sin_ad; + *Ty_y= dr_cos_ad; + *Tx_1= x1m - dr_cos_ad*x0m + dr_sin_ad*y0m; + *Ty_1= y1m - dr_sin_ad*x0m - dr_cos_ad*y0m; +} + + +void +do_interpolation ( + double Tx_x, double Ty_x, + double Tx_y, double Ty_y, + double Tx_1, double Ty_1, + int x0max, int y0max,// initial size + int x1max, int y1max,// output size + const double * img0, + double * img1 + ) +{ + + for (int i=0; i< x1max; i++) { + for (int j=0; j< y1max; j++) { + double x0i= Tx_x * i + Tx_y * j + Tx_1; + double y0i= Ty_x * i + Ty_y * j + Ty_1; + + if ( x0i < 0 ) x0i= 0; + else + if (x0i >= x0max-1 ) x0i= x0max - 1.00001; + + if ( y0i < 0 ) y0i= 0; + else + if (y0i >= y0max-1 ) y0i= y0max - 1.00001; + + int x0idx= (int) x0i; + int y0idx= (int) y0i; + + double frac_r= x0i- x0idx; + double frac_l= 1 - frac_r; + double frac_d= y0i- y0idx; + double frac_u= 1 - frac_d; + + int pix_lu= (y0idx+0) + (x0idx+0) * y0max ; + int pix_ru= (y0idx+0) + (x0idx+1) * y0max ; + int pix_ld= (y0idx+1) + (x0idx+0) * y0max ; + int pix_rd= (y0idx+1) + (x0idx+1) * y0max ; + + img1[ i*y1max + j ]= + frac_l*frac_u* img0[ pix_lu ] + + frac_r*frac_u* img0[ pix_ru ] + + frac_l*frac_d* img0[ pix_ld ] + + frac_r*frac_d* img0[ pix_rd ]; + + } + } +} +
deleted file mode 100644 --- a/std2.m +++ /dev/null @@ -1,38 +0,0 @@ -## Copyright (C) 2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} @var{s}= std2 (@var{I}) -## returns the standard deviation for a 2d real type matrix. -## Uses @code{std (I(:))} -## @end deftypefn -## @seealso{mean2,std} - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 01/08/2000 - -function s = std2 (I) - - if !(nargin == 1) - usage ("std2(I)"); - endif - - if !(is_matrix(I) && isreal(I)) - error("argument must be a real type matrix"); - endif - - s = std (I(:)); -endfunction
deleted file mode 100644 --- a/stretchlim.m +++ /dev/null @@ -1,209 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I},@var{TOL}) -## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{I}) -## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB},@var{TOL}) -## @deftypefnx {Function File} {@var{LOW_HIGH} = } stretchlim (@var{RGB}) -## Finds limits to contrast stretch an image -## -## @code{LOW_HIGH=stretchlim(I,TOL)} returns a vector @var{LOW_HIGH} -## which contains a pair of intensities which can be used in -## @code{imadjust} to stretch the contrast of an image, first of them -## will be lower value (@code{imadjust} would assign 0 to it) and second -## is the upper bound. @var{TOL} specifies the fraction of the image to -## saturate at lower and upper limits. It can be a vector of length 2: -## @code{[LOW_FRACT, HIGH_FRACT]}, or it can be a scalar, in that case -## @code{[LOW_FRACT, HIGH_FRACT]=[TOL, 1-TOL]}. -## -## @var{TOL} can't be larger than 0.50 and for TOL=0 then -## @code{LOW_HIGH=[min(I(:)), max(I(:))]}. -## -## @code{LOW_HIGH=stretchlim(I)} behaves as described but defaults -## @var{TOL} to @code{[0.01, 0.99]}. -## -## @code{LOW_HIGH=stretchlim(RGB,TOL)} returns a 2-by-3 matrix in -## @var{LOW_HIGH} of lower and upper values to saturate for each plane -## of the RGB image in M-by-N-by-3 array @var{RGB}. @var{TOL} is a -## vector or a scalar, as described above, and the same fractions are -## applied for each plane. -## -## @code{LOW_HIGH=stretchlim(RGB)} uses @code{[0.01, 0.99]} as default -## value for @var{TOL}. -## -## @strong{Notes:} -## -## Values in @var{LOW_HIGH} are of type double and comprised between 0 -## and 1 regardless class of input image. -## -## @strong{Compatibility notes:} -## -## @itemize @bullet -## @item -## int* and uint* types are still not implemented (waiting for support -## in Octave 2.1.58). -## @item -## This function tries to find limits that are nearer to saturate -## requested interval. So, for instance, if you requested a 5% and it -## has to choose between discarding a 1% and a 7%, it will choose the -## later despite being more than requested. This should be test against -## MATLAB behaviour. -## @end itemize -## -## @end deftypefn -## @seealso imadjust - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function LOW_HIGH = stretchlim(image, TOL) - if (nargin<1 || nargin>2) - usage("LOW_HIGH=stretchlim(I [, TOL]), LOW_HIGH=stretchlim(RGB [, TOL])"); - endif - - if(!ismatrix(image)) - error("stretchlim: image should be a matrix"); - endif - - ## Prepare limits - if(nargin==1) - low_count=0.01; - high_count=0.01; ## we use this definition in __stretchlim_plane__ - else - if(isscalar(TOL)) - if(TOL<0 || TOL>=0.5) - error("stretchlim: TOL out of bounds. Expected: 0<=TOL<0.5"); - endif - low_count=TOL; - high_count=TOL; ## as before... - elseif(isvector(TOL)) - if(length(TOL)!=2) - error("stretchlim: TOL length must be 2."); - endif - low_count=TOL(1); - high_count=1-TOL(2); ## as before... - else - error("stretchlim: TOL contains an invalid value."); - endif - endif - - ## well use size of image several times... - simage=size(image); - - ## Convert fractions to pixels - psimage=prod(simage(1:2)); - low_count*=psimage; - high_count*=psimage; - - if(length(simage)<=2) - ## intensity - LOW_HIGH=__stretchlim_plane__(image, low_count, high_count); - elseif(length(simage)==3 && simage(3)==3) - ## RGB - LOW_HIGH=zeros(2,3); - for i=1:3 - LOW_HIGH(:,i)=__stretchlim_plane__(image(:,:,i), low_count, \ - high_count); - endfor - else - error("stretchlim: invalid image."); - endif -endfunction - - -## Processes a plane -## high_count is defined so that high_count=elements is the same as -## low_count=elements (and not total_elements-elements) -function LOW_HIGH = __stretchlim_plane__(plane, low_count, high_count) - ## check exceptions - if(low_count==0 && high_count==0) - LOW_HIGH=[min(plane(:)); max(plane(:))]; - else - - ## we sort values - sorted=sort(plane(:)); - - low=sorted(round(low_count+1)); - pos=find(sorted>low); - if(length(pos)>0) - low2=sorted(pos(1)); - d1=low_count-sum(sorted<low); - d2=sum(sorted<low2)-low_count; - if(d2<d1) - low=low2; - endif - endif - - high=sorted(end-round(high_count)); - pos=find(sorted<high); - if(length(pos)>0) - high2=sorted(pos(end)); - d1=high_count-sum(sorted>high); - d2=sum(sorted>high2)-high_count; - if(d2<d1) - high=high2; - endif - endif - - ## set result variable - LOW_HIGH=[low;high]; - endif -endfunction - -%!demo -%! stretchlim([1:100]) -%! # This discards 1% of data from each end, 1 and 100. -%! # So result should be [2;99] - -%!# some invalid params -%!error(stretchlim()); -%!error(stretchlim("bad parameter")); -%!error(stretchlim(zeros(10,10,4))); -%!error(stretchlim(zeros(10,10,3,2))); -%!error(stretchlim(zeros(10,10),"bad parameter")); -%!error(stretchlim(zeros(10,10),0.01,2)); - - -%!# default param -%!assert(stretchlim([1:100]),[2;99]); - -%!# scalar TOL -%!assert(stretchlim([1:100],0.01),[2;99]); - -%!# vector TOL -%!assert(stretchlim([1:100],[0.01,0.98]),[2;98]); - -%!# TOL=0 -%!assert(stretchlim([1:100],0),[1;100]); - -%!# non uniform histogram tests -%!assert(stretchlim([1,ones(1,90)*2,92:100],0.05),[2;95]); -%!assert(stretchlim([1,ones(1,4)*2,6:100],0.05),[6;95]); - -%!# test limit rounding... -%!assert(stretchlim([1,ones(1,5)*2,7:100],0.05),[7;95]); # 6% lost -%!assert(stretchlim([1,ones(1,6)*2,8:100],0.05),[8;95]); # 7% lost -%!assert(stretchlim([1,ones(1,7)*2,9:100],0.05),[9;95]); # 8% lost -%!assert(stretchlim([1,ones(1,8)*2,10:100],0.05),[2;95]); # now he limit at 2 => 1% lost - -%!# test RGB -%!test -%! RGB=zeros(100,1,3); -%! RGB(:,:,1)=[1:100]; -%! RGB(:,:,2)=[2:2:200]; -%! RGB(:,:,3)=[4:4:400]; -%! assert(stretchlim(RGB),[2,4,8;99,198,396]); -
deleted file mode 100644 --- a/summer.m +++ /dev/null @@ -1,52 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} summer (@var{n}) -## Create color colormap. -## (green to yellow) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> -## Date: 06/03/2000 -function map = summer (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("summer: argument must be a scalar"); - endif - else - usage ("summer (number)"); - endif - - if (number == 1) - map = [0, 0.5, 0.4]; - elseif (number > 1) - r = (0:number - 1)' ./ (number - 1); - g = 0.5 + r ./ 2; - b = 0.4 * ones (number, 1); - - map = [r, g, b]; - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/testimio.m +++ /dev/null @@ -1,56 +0,0 @@ -## This program is public domain. - -## build image for image r/w tests -x=linspace(-8,8,200); -[xx,yy]=meshgrid(x,x); -r=sqrt(xx.^2+yy.^2) + eps; -map=colormap(hsv); -A=sin(r)./r; -minval = min(A(:)); -maxval = max(A(:)); -z = round ((A-minval)/(maxval - minval) * (rows(colormap) - 1)) + 1; -Rw=Gw=Bw=z; -Rw(:)=fix(255*map(z,1)); -Gw(:)=fix(255*map(z,2)); -Bw(:)=fix(255*map(z,3)); -Aw=fix(255*(1-r/max(r(:)))); ## Fade to nothing at the corners - -if exist("jpgwrite") - disp(">jpgwrite"); - jpgwrite('test.jpg',Rw,Gw,Bw); - stats=stat("test.jpg"); - assert(stats.size,6423); - disp(">jpgread"); - im = jpgread('test.jpg'); - Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3); - assert(all(Rw(:)-double(Rr(:))<35)); - assert(all(Gw(:)-double(Gr(:))<35)); - assert(all(Bw(:)-double(Br(:))<35)); - unlink('test.jpg'); -else - disp(">jpgread ... not available"); - disp(">jpgwrite ... not available"); -endif - -if exist("pngwrite") - disp(">pngwrite"); - pngwrite('test.png',Rw,Gw,Bw,Aw); - stats=stat("test.png"); - assert(stats.size,24738); - disp(">pngread"); - im = pngread('test.png'); - Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3); - assert(all(double(Rr(:))==Rw(:))); - assert(all(double(Gr(:))==Gw(:))); - assert(all(double(Br(:))==Bw(:))); - [im,Ar] = pngread('test.png'); - Rr = im(:,:,1); Gr = im(:,:,2); Br = im(:,:,3); - assert(all(double(Rr(:))==Rw(:))); - assert(all(double(Gr(:))==Gw(:))); - assert(all(double(Br(:))==Bw(:))); - assert(all(double(Ar(:))==Aw(:))); - unlink('test.png'); -else - disp(">pngread ... not available"); - disp(">pngwrite ... not available"); -endif
deleted file mode 100644 --- a/uintlut.m +++ /dev/null @@ -1,57 +0,0 @@ -## Copyright (C) 2004 Josep Mones i Teixidor -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {@var{B} = } uintlut (@var{A},@var{LUT}) -## Computes matrix B by using A as an index to lookup table LUT. -## -## B = uintlut(A, LUT) calculates a matrix B by using @var{LUT} as a -## lookup table indexed by values in @var{A}. -## -## B class is the same as @var{LUT}. -## @end deftypefn - -## Author: Josep Mones i Teixidor <jmones@puntbarra.com> - -function B = uintlut(A, LUT) - if (nargin != 2) - usage("B = uintlut(A, LUT)"); - endif - - ## We convert indexing array A to double since even CVS version of - ## Octave is unable to use non-double arrays as indexing types. This - ## won't be needed in the future eventually. - B=LUT(double(A)); -endfunction - -%!demo -%! uintlut(uint8([1,2,3,4]),uint8([255:-1:0])); -%! % Returns a uint8 array [255,254,253,252] - -%!assert(uintlut(uint8([1,2,3,4]),uint8([255:-1:0])), uint8([255:-1:252])); -%!assert(uintlut(uint16([1,2,3,4]),uint16([255:-1:0])), uint16([255:-1:252])); -%!assert(uintlut(uint32([1,2,3,4]),uint32([255:-1:0])), uint32([255:-1:252])); -%!assert(uintlut(uint64([1,2,3,4]),uint64([255:-1:0])), uint64([255:-1:252])); - -% -% $Log$ -% Revision 1.2 2004/08/11 15:04:59 pkienzle -% Convert dos line endings to unix line endings -% -% Revision 1.1 2004/08/08 21:20:25 jmones -% uintlut and padarray functions added -% -%
deleted file mode 100644 --- a/white.m +++ /dev/null @@ -1,46 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} white (@var{n}) -## Create color colormap. -## (completly white) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = white (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("white: argument must be a scalar"); - endif - else - usage ("white (number)"); - endif - - if (number > 0) - map = ones (number, 3); - else - map = []; - endif - -endfunction
deleted file mode 100644 --- a/winter.m +++ /dev/null @@ -1,52 +0,0 @@ -## Copyright (C) 1999,2000 Kai Habel -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -## -*- texinfo -*- -## @deftypefn {Function File} {} winter (@var{n}) -## Create color colormap. -## (blue to green) -## The argument @var{n} should be a scalar. If it -## is omitted, the length of the current colormap or 64 is assumed. -## @end deftypefn -## @seealso{colormap} - -## Author: Kai Habel <kai.habel@gmx.de> - -function map = winter (number) - - if (nargin == 0) - number = rows (colormap); - elseif (nargin == 1) - if (! is_scalar (number)) - error ("winter: argument must be a scalar"); - endif - else - usage ("winter (number)"); - endif - - if (number == 1) - map = [0, 0, 1]; - elseif (number > 1) - r = zeros (number, 1); - g = (0:number - 1)' ./ (number - 1); - b = 1 - g ./ 2; - - map = [r, g, b]; - else - map = []; - endif - -endfunction