Image Processing and Analysis in Guile
a Computer Vision functional programming library
This is a maintenance release, which introduces new interfaces and some performance improvements.
The local minima and maxima interfaces have been improved, and now support the full set of options provided by Vigra, to our request (thank you Benjamin!). In addition there has been a few bugs fixed, including one we detected while working on Guile-CV local minima bindigs.
The f32vector-delineate core functionality has been moved to libguile-cv. Note that all memory allocation - except for some local variables - still is being performed in scheme.
This move makes im-delineate work almost twice as fast. Because all memory allocation still is done in scheme, and not in C, I am very confortable with this approach. When Guile has an AOT compiler that compiles fixed size floating points and small integers operations and vector loops for these that runs as fast as in C, and I am prety confident that it will happen, maybe not tomorrow, but it will happen, we will revert these and use Guile Scheme again.
This is a 'milestone' release, which introduces image texture measures. In addition (a) the default installation locations have changed; (b) there is a new configure option; (c) some new insterfaces; (d) matrix multiplication performances have been greatly improved; (d) a few interface (name) have changed.
Installation location changes
The default and
In the above,
This change makes Guile-CV compatible with the
GNU Coding Standards, but it also implies that, unless you use the new
configure option describe below, you will have to augment both Guile's
New configure option
The configure option --with-guile-site has been added, used to explicitly ask Guile-CV's source modules and compiled files to be installed using Guile's global site and site-ccache directories respectively (see Guile-CV's installation 'Notes' for more on this).
It will only be honored if (and only if) it is passed as:
The following methods have been renamed, and the matrix
The former two methods, related to matrix multiplication, are now procedures. The later two are methods: see the manual to see the different ways you may call them.
Likewise, these were methods, they are now procedures.
These matrix operations (actually, their corresponding f32vector-* core functionality) have been moved to libguile-cv. Note that all memory allocation - except for some per-function local variables - still is being performed in scheme.
This move makes a small black and white 515 x 515 image matrix multiplication by itself (for the sake of timing things) execute in 0.228 sec instead of 29.51 sec - that is 134x faster.
In image processing 'real world', this would be a tiny image, being 134x faster for these linear algebra procedures makes a huge difference. Until Guile offers 32 bits floating point and integer calculus performances equal to or faster of those we get using libguile-cv, and since memory allocation is done in scheme, I am confortable with this approach.
new interface vigra_nonlocalmean_c (introduced in Jan 2018), has an argument that has been renamed;
the vigra_medianfilter_c function (updated in Jan 2018 as well) takes an additional 'out-of-bound strategy' argument.
in the module (cv support latex) - undocumented but quite usefull procedure, to 'prepare' text to be added to images (see im-compose) - the optional keyword [#:res 72] argument was actually not used in the core of the procedure, fixed.
A clipping bug has been fixed in vigra_exportgrayimage_c, vigra_exportrgbimage_c and vigra_exportrgbaimage_c. A new vigra_clipimage_c function is available and Guile-CV uses it.
Configuring Guile for Guile-CV
Previously, these two procedures were respectively named im-fill and im-fill-channel, but that was a bit ambiguous.
New optional keyword,
Return n-label, not n-object. The number of labels correspond to the highest label value + 1: earlier version of Guile-CV, prior to version 1.8.0, did return the number of objects, which correspond to the highest label value. This was less then optimal, since not only 0.0 is a label, but other procedures, im-features for example, do consider and return a feature object for the background as well.
Note that Vigra C functions return the label highest value, but the vigra-label-all function starts to label using 1.0, so in this case, the label highest value is also the number of label used, hence im-label-all-channel has to return 'n-object' and not '(+ n-object 1)', fixed. I don't like this, for me it is inconsistent, and im-label-all should start to label using 0.0 as well, so I mailed the Vigra folks, let's see...
Consistency between im-label, im-label-all and im-features. All these already named their argument 'n-label', but it actually ment 'n-object'. I changed all this - and the segmentation related code as well - so it is consistent everywhere in the code. And now, the n-label argument value also correspond to the length of the list of features returned, so much better.
Vigra C functions, at the contrary, expect 'n-object', or expressed differently, expect the label highest value, which correspond to (- n-label 1). This is also consistent everywhere in the code now.
Now accepts more then one image.
We had and-l already. There are (well known among schemers) situations where you need a function that works on lists.
Composite images only differs to others in the sence that they can have more then 3 channels, any number of channels actually, the 4th _not_ being the traditional alpha channel. Each channel holds on specific information, depending on the application domaim. It is sometime necessary to visualize these though, in which case they must be 'converted' to RGB images, hence this new procedure. This is a 'work in progress': as it is, it will only work if the composite image has 4 channels. In this first implementation, the algorithm will super impose the 4th channel to the RGB's, so one says 'white pixels always win' (this because the 4th channel is (generally) associated with the White 'color').
It was a bad idea to make this internal procedure public, and users can call (apply im-=? ...) anyway.
Calls im-rgb->gray-1, which was unnecessary calling float-round at each step, and I also noticed that recursive tail call procedures have a tiny penalty compared to loop, so rewrote both. Now, in addition, both procedures will split their work in between as many core as available, except if the parameter %use-par-map has been set to #f. On my laptop - i5-2450M CPU @ 2.50GHz × 4 and 5.7GB of mem - both procedures are now 3 to 4 times faster.
Labels are 'discrete' floats, by definition, so we can use = instead of float=?, which is 3 to 4 times faster.
Area, left, top, right, bottom values are discrete floats, use float->int, not float-round.
Till Guile-3.0 becomes available, I decided to temporarily rewrite the math, linear algebra and logical 'low level' procedures in C. Tests performed on my laptop - i5-2450M CPU @ 2.50GHz × 4 and 5.7GB of mem - using GRAY and RGB test images of 2718 x 1732 show gains in the range of 23x to 100x faster, depending on the operation and wether images involved have 1 or more channels (though in Guile-CV, unless the user sets the %use-par-map parameter to #f, all multi channel operations are multi threaded).
Because all memory allocation still is done in scheme, and not in C, I am very confortable with this approach, as I said, till we have an AOT compiler that compiles fixed size floating point and small integers operations and vector loops for these that runs as fast as in C, and I am prety confident that it will happen, maybe not tomorrow, but it will happen.
That commit introduces - kindly implemented by Benjamin Seppke upon our request - the following new features: centre of mass, perimeter, skewness, kurtosis.
Adding an optional (scale #f) argument. Till now, images pixel values would be always scaled at save time, unless saving the file using tif. This was really less then optimal because (a) tif preserves values, but no image viewer knows how to display these Guile-CV 32 bits float images (they beleive these are RGBA images) and (b) scaling at save time totally destroyed the results of im memory calcuations ... What we really want here, most of the time at least, and hence it becomes the default from now on, is what is called 'clipping': pixel values are ‘clipped’, which means that values < 0 are saved as 0, values > 255 are saved as 255, and otherwise are saved unchanged.
Previously, these procedures were using the name 'inverse', but that was not 'optimal', fixed.
major-ev-x, major-ev-y, minor-ev-x, minor-ev-y, major-axis, minor-axis, angle, center-mass-x, center-mass-y, perimeter, skewness, kurtosis, circularity, aspect-ratio, roundness.
major-ev-x, major-ev-y, minor-ev-x, minor-ev-y, major-axis, minor-axis, angle, center-mass-x, center-mass-y, perimeter, skewness-r, skewness-g, skewness-b, kurtosis-r, kurtosis-g, kurtosis-b, circularity, aspect-ratio, roundness.
both procedures have been 'relaxed' and do not check anymore that either the value or pixel values respectively are in the [0 255] range, as doing so was actually incorrect: images need to be normalized and scaled (as in bringing their pixel values in the [0 255] range) only to be displayed, but otherwise, their should be no such limitations.
was returning #f for BLACK and WHITE images, so either composed of eiher 0.0 or 255.0, fixed.
Adding an optional #:key (val 255.0), since we need to be able to normalize to specific values in some circumstances, such as, for example, to normalize gray level co-occurrence matrices.
The arguments order has been changed for 'vector proc default' not 'proc default vector', because it is the order we use in im-reduce and im-reduce-channel - as [almost] all other im-* procedures or methods take an image as their first argument. As a user, it is also a bit more naturel, imo at least, to 'reduce image using proc, return default if the image is empty'.
All linear algebra matrix methods now accept any number of images or channels. Note that due to the inherent checks between lines and columns of intermediate results, im-multiply-channel and im-divide-channel methods arguments must be a series of at least one tuple(s) composed of three values - channel width height - represented in the manual as: c1 w1 h1 c2 w2 h2 c3 w3 h3 …
Updated so its interface is 'identical' to im-map and friends, and a typical call now looks like: im-collect what i1 i2 i3 … (instead of im-collect images what).
the width and height of the result normalized image were inadvertently inverted, now fixed.
the sub results were inadvertently using 'n' instead of 'p' to compute their destination position in the 'n x p' cells returned result f32vector, now fixed.
This is the first public release of Guile-CV, earlier releases were made available to GNU evaluators and Savannah hackers only.
packages: inputenc, fontenc, lmodern, xcolor, booktabs, siunitx, iwona
The GNU evaluation of Guile-CV has been completed on March the 11th, 2017, but due to backlog, we've been informed then that its approval step would take another five weeks, so we decided to upload it on Savannah non gnu in the mean time, done!
A couple of months ago, we started to work on Guile-CV, a Computer Vision functional library for the Guile Scheme language, and now is the right time for it to be evaluated to be part of the GNU Project.