Review of Generic Image Library (GIL) begins today, Oct5, 2006

The review of Generic Image Library (GIL) begins today, October 5, 2006, and continues through October 15, 2006. Please download the library at: http://opensource.adobe.com/gil. Minor change are being made regularly (daily), so check the site often for updates. I highly recommend viewing the 55 minute Breeze presentation describing the library at: http://opensource.adobe.com/gil/presentation/index.htm A tutorial is available at: http://opensource.adobe.com/gil/gil_tutorial.pdf A design guide is availage at: http://opensource.adobe.com/gil/gil_design_guide.pdf Description: The Generic Image Library (GIL) is a C++ library that abstracts the image representation from operations on images. It allows for writing the image processing algorithm once and having it work for images in any color space, channel depth and pixel organization, or even synthetic images, without compromising the performance. GIL has an extension mechanism that allows for adding extra functionality. Two extensions are currently provided – one for image I/O and one for handling images whose properties are specified at run-time. Review questions: Please always explicitly state in your review, whether you think the library should be accepted into Boost. You might want to comment on the following questions: - What is your evaluation of the design? - What is your evaluation of the implementation? - What is your evaluation of the documentation? - What is your evaluation of the potential usefulness of the library? - Did you try to use the library? With what compiler? Did you have any problems? - How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? - Are you knowledgeable about the problem domain? Tom Brinkman

Tom Brinkman wrote:
The review of Generic Image Library (GIL) begins today, October 5, 2006, and continues through October 15, 2006.
I'd like to do a formal review of GIL. But, given the extent of the library and the time constraint, it's hard to do it on or before Oct 15. Is it possible to have an extension? Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Tom Brinkman wrote:
The review of Generic Image Library (GIL) begins today, October 5, 2006, and continues through October 15, 2006.
I'd like to do a formal review of GIL. But, given the extent of the library and the time constraint, it's hard to do it on or before Oct 15. Is it possible to have an extension?
I second that request. I'm struggling to find some time to do the library justice, hopefully over the coming weekend. Thanks, Stefan -- ...ich hab' noch einen Koffer in Berlin...

I vote that GIL is rejected this time. This is not because I doubt the usefulness or quality of implementation, more due to the fact that there is at least one other generic library (Vigra), which covers much of the same field, that has been around longer, and supplies many more algorithms.
- What is your evaluation of the design?
The design is GIL's strong point. It provides useful extensions to STL iterators, reference views on data etc. Similar interfaces are provided also in other libraries, but GIL looks like being up to par (without doing detailed comparison with MTL, Blitz and others). It already uses Boost components, and claims STL compliance.
- What is your evaluation of the implementation?
The implementation also looks up to the task, for what it does. Everything I saw looks clean and is separated into small units. Naming is generally to the point. The systematic naming schemes are informative, but should be exposed more prominently in docs.
- What is your evaluation of the potential usefulness of the library?
GIL provides useful extensions to STL algorithms (copy, generate, transform), extended (multidimensional, strided) iteration support, non-ownership data views, and convenience classes for various color encodings. This is very useful, but it does not provide full image processing. GIL lacks support for signal processing. Pixel images are just sample points of a continuous space. Therefore algorithms from numerical analysis are regularly used on images: FFT, convolution kernels for 2D filtering etc. Vigra provides interface to FFTW, filters and convolution. GIL may have better design. But both Vigra and Anti-Grain are richer. I would also require transparent handling of those dreary outer-edge conditions. This is glossed over in tutorial. How do I switch between treating the (-1, -1) lines as black (zero) and as copy of the outer (0,0) edges? Would GIL look better if it is only viewed as a generic N-dimensional data access framework? Then we should be comparing it to Matrix Template Library. Lubomir has already answered Oleg that this is not the intention. So a merge with or reimplementation of Vigra/AGG functionality seems in order. This could maybe be just a rounded package of convenience functions that supports common transformations efficently, with minimal end-user typing (keystrokes). Oh, I saw just now that some more algorithms were posted recently. Good, but late. Were they included in the review submission? Or more like proof of concept sketches? Again, GIL looks good for what it does. Actually, after this review I'm more inclined to use it than before, but not for image processing - rather for some complex iteration tasks over plain 1-dim data.
- What is your evaluation of the documentation?
Not so well organized, and a little thin. The design document interleaves technical detail and very brief overview. The tutorial is impressionistic, and the code examples look like it's going to be a rough ride using GIL (lots of indexing src[x+1], src[x-1] etc, - that's how image processing looks in C, can't we have kernel functors instead?) Concept docs looks as if copied verbatim from header files, though now I know it isn't so. They look cluttered. Documentation is often scanty, or inane repetition of class/concept names. Perhaps the authors trust that naming is so good that code will be self-explaining. Maybe so, but when it's broken up in many pages, the overview one gets in the header files disappears. Perhaps a left-side browsing tree would help? The Models reference doc tree almost but not quite repeats the Concepts tree. I'm not sure whether I'd like them merged or just cross-linked, but the present setup separates related things. Links in the tutorial point to places that don't help understanding at all, whereas the places where something substantial is said are buried 2-4 links away from the TOC of reference docs. (Eg class image_view. I posted about this a while ago.) I did watch the Breeze presentation a while ago, and again today, and I still don't think one should have to sit through something like that to get started with a library in a familiar field. There are some good breakdowns of names and overviews of available classes/functions that should be typed out and linked up with browsable docs.
- Did you try to use the library? With what compiler? Did you have any problems?
No. I usually just read interfaces of several comparable libraries until I choose which one to use.
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
In-depth glance: Browsing docs for a couple hours, browsing header files for a few hours.
- Are you knowledgeable about the problem domain?
Somewhat. I have written a published app for image generation and processing some time ago, and rewritten part of it in semi-generic code more recently. I would have loved to have something like GIL before, but would actually go for AGG or Vigra. === EOR ===================================== This is my first review for Boost. I've used some Boost code since about 1.25, followed this list about as long, but am not a professional programmer. I know a proper "review" should go a little deeper than the above, so feel free to factor my vote by 2/3 or something. (I'd actually prefer that, wouldn't want to be responsible for rejection of something I just failed to comprehend...) Cheers, rasmus ekman

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of rasmus ekman Sent: Thursday, October 12, 2006 7:25 PM To: boost@lists.boost.org Subject: [boost] Review of Generic Image Library (GIL)
I vote that GIL is rejected this time.
This is not because I doubt the usefulness or quality of implementation, more due to the fact that there is at least one other generic library (Vigra), which covers much of the same field, that has been around longer, and supplies many more algorithms.
First of all, as far as we know we don't have a formal proposal from Vigra on the table, so we feel it is unfair to reject for this reason. This is like rejecting a job interview candidate because there is someone out there who is more knowledgeable. Will that other person be even interested in the job you are offering? Is knowledge the only skill you are looking for and, if not, does that other person have all other required skills? Will the current job candidate be interested in interviewing for your job again once rejected? Often not. Here is another perhaps more important question to the boost audience: If you have to make a choice, would you choose a library with a better design and a minimal set of existing algorithms or a library that has more stuff in it, but with not so good a design? Please note: We are NOT suggesting that Vigra has inferior design. In fact, we praise Vigra in our design guide. We refrain from comparison, at the very least, because Vigra is not even on the table. However, we want to address this logical question if design is more important than present functionality, because it seems to be in the basis for Rasmus's vote. A related question: Which one is easier - building new functionality on top of a solid design, or extending the design of a library with lots of existing algorithms that are built on top of the old design?
- What is your evaluation of the design?
The design is GIL's strong point. It provides useful extensions to STL iterators, reference views on data etc. Similar interfaces are provided also in other libraries, but GIL looks like being up to par (without doing detailed comparison with MTL, Blitz and others). It already uses Boost components, and claims STL compliance.
Thank you.
- What is your evaluation of the implementation?
The implementation also looks up to the task, for what it does. Everything I saw looks clean and is separated into small units. Naming is generally to the point. The systematic naming schemes are informative, but should be exposed more prominently in docs.
- What is your evaluation of the potential usefulness of the library?
GIL provides useful extensions to STL algorithms (copy, generate, transform), extended (multidimensional, strided) iteration support, non-ownership data views, and convenience classes for various color encodings.
This is very useful, but it does not provide full image processing. GIL lacks support for signal processing. Pixel images are just sample points of a continuous space. Therefore algorithms from numerical analysis are regularly used on images: FFT, convolution kernels for 2D filtering etc.
FYI, we do have image processing algorithms in our GIL numeric extension. You can do arbitraty affine transformations, nearest-neighbor and bilinear resampling and convolution. It has no external dependencies, so if you need this stuff you can use it even if not in boost. It is not currently part of the review, but if GIL makes it into boost one day we may have a follow-up proposal. Why not submit together? Aside from the fact that the numeric extension is far from being comprehensive and well optimized, we want to see GIL used extensively and make sure the fundamentals are absolutely solid before making heavy-duty algorithms, because it is much harder to change your foundations after you have built the house (which suggests my opinion to the earlier question I posed).
Vigra provides interface to FFTW, filters and convolution. GIL may have better design. But both Vigra and Anti-Grain are richer.
The Vigra question is discussed above. I don't think we should even mention Anti-Grain here, as it has a very different focus, as discussed in a separate thread.
I would also require transparent handling of those dreary outer-edge conditions. This is glossed over in tutorial. How do I switch between treating the (-1, -1) lines as black (zero) and as copy of the outer (0,0) edges?
The goal of the tutorial is not to show you how to make a production-quality algorithm, but to teach you the basics of the GIL interface. Once you know how to navigate the pixels in the image, how to get/set their values and once you understand what the performance implications are, it should be straightforward for you to handle the corner cases. We certainly don't suggest using the x_gradient algorithm as-is. It doesn't handle corner cases, and central difference is a poor approximation to the gradient. On the other hand, real GIL algorithms do handle corner cases. Our convolution, for example, gives you a multitude of options for the corner cases - you can ignore them, pad them, clear them, reuse the nearest value, etc.
Would GIL look better if it is only viewed as a generic N-dimensional data access framework? Then we should be comparing it to Matrix Template Library. Lubomir has already answered Oleg that this is not the intention.
So a merge with or reimplementation of Vigra/AGG functionality seems in order. This could maybe be just a rounded package of convenience functions that supports common transformations efficently, with minimal end-user typing (keystrokes).
Merging between GIL/Vigra or especially GIL/AGG would be interesting. But how is your rejection helping here? If anything, it makes this possibility less likely.
Oh, I saw just now that some more algorithms were posted recently. Good, but late. Were they included in the review submission? Or more like proof of concept sketches?
Why is it late? The review period is not over. And I am not sure which algorithms you are referring to. The numeric extension is not part of the submission for the above-listed reasons, and it was posted before the review began.
Again, GIL looks good for what it does. Actually, after this review I'm more inclined to use it than before, but not for image processing - rather for some complex iteration tasks over plain 1-dim data.
- What is your evaluation of the documentation?
Not so well organized, and a little thin. The design document interleaves technical detail and very brief overview. The tutorial is impressionistic, and the code examples look like it's going to be a rough ride using GIL (lots of indexing src[x+1], src[x-1] etc, - that's how image processing looks in C, can't we have kernel functors instead?)
Sure you can - see the kernel from the numeric extension as an example. Being able to use the indexing operator and being able to use a kernel functor are not exclusive.
Concept docs looks as if copied verbatim from header files, though now I know it isn't so. They look cluttered. Documentation is often scanty, or inane repetition of class/concept names. Perhaps the authors trust that naming is so good that code will be self-explaining.
Not at all. In addition to the design guide and tutorial, we have Doxygen documentation for every public interface and lots of private ones. Which part of the code you feel is not well documented?
Maybe so, but when it's broken up in many pages, the overview one gets in the header files disappears. Perhaps a left-side browsing tree would help?
The Models reference doc tree almost but not quite repeats the Concepts tree.
Because we want to separate the models from the concepts. This is common in other libraries too.
I'm not sure whether I'd like them merged or just cross-linked, but the present setup separates related things.
We do often provide links from the models to their concepts. But you are right, they are not consistently present. In the design guide after we discussing a concept we point to its models.
Links in the tutorial point to places that don't help understanding at all, whereas the places where something substantial is said are buried 2-4 links away from the TOC of reference docs. (Eg class image_view. I posted about this a while ago.)
Rasmus - these links are automatically generated by Doxygen, which might explain why some of them may not feel logically placed. We could look into suppressing some of these links that don't make sense. Thanks for the suggestion. Thanks for your review, Lubomir & Hailin

Lubomir Bourdev wrote:
-----Original Message----- From: rasmus ekman
I vote that GIL is rejected this time.
This is not because I doubt the usefulness or quality of implementation, more due to the fact that there is at least one other generic library (Vigra), which covers much of the same field, that has been around longer, and supplies many more algorithms.
First of all, as far as we know we don't have a formal proposal from Vigra on the table, so we feel it is unfair to reject for this reason.
As I said later on, my review is less based on detailed experience with all the libraries I mention, and more on an end-user perspective. As end user I unashamedly ask, "what can this library do for me" and: "is there anything better around?" I want to rewrite a middlesized graphics app, and the libraries used have major impact. Today I would choose some other library than GIL, and wish that it was submitted to Boost so the authors would fix up the interfaces (and docs). I did not hold back since it seems from here that you (the authors of GIL) have very robust skills and can trust your own judgment also in the face of somewhat whiny criticism. I absolutely do not intend to seem dismissive, more posing challenges I'm near-certain that you (and GIL) can meet. The worries I try to express are: (1) Will the design work out in the long run? - GIL is not proven yet. (2) Where is GIL going? - If it is accepted, this gives more or less blank cheque to make additions - or not. Until we see the additions made, there's no knowing if they will work out, and how rich the library will end up being. So, is GIL finished now? Are there only a few technotes to add? And if not, was the submission premature? Note: The last is a trick question. You can also use the review to get input on the library, make the changes you can, and resubmit quite soon. I believe this is a valid and accepted way of using the review process. Other boosters can tell if I got that wrong.
[snip] Will the current job candidate be interested in interviewing for your job again once rejected? Often not.
No, and it's maybe a problem. Boost reviews seem to have burned several people, leaving them feeling unfairly treated. This is not (just) recent, I've noted it in some cases over the last 5 years. There are boosters better placed to tell you whether there might be problems with the review process - or with the pre-review process.
- What is your evaluation of the potential usefulness of the library?
[snip] GIL lacks support for signal processing.
FYI, we do have image processing algorithms in our GIL numeric extension. [snip] It is not currently part of the review, but if GIL makes it into boost one day we may have a follow-up proposal. Why not submit together? Aside from the fact that the numeric extension is far from being comprehensive and well optimized, we want to see GIL used extensively and make sure the fundamentals are absolutely solid
Exactly. Can I say it now? Me too!
before making heavy-duty algorithms, because it is much harder to change your foundations after you have built the house
So a merge with or reimplementation of Vigra/AGG functionality seems in order.
Merging between GIL/Vigra or especially GIL/AGG would be interesting. But how is your rejection helping here? If anything, it makes this possibility less likely.
I hope I have covered this above: Review rejection is often not final. The embrace is often just two steps behind it, if most worries are addressed. - sometimes just if motivation is provided: You are after all the domain experts.
Oh, I saw just now that some more algorithms were posted recently. Good, but late. Were they included in the review submission? Or more like proof of concept sketches?
Why is it late? The review period is not over. And I am not sure which algorithms you are referring to. The numeric extension is not part of the submission for the above-listed reasons, and it was posted before the review began.
From the download page: "It is in a very early stage of development; it is not documented and has not been optimized for performance." I'm sure you're partly just being modest here, but I didn't consider downloading it when the review was first announced, then didn't look back until yesterday.
Concept docs looks as if copied verbatim from header files, though now I know it isn't so. They look cluttered. Documentation is often scanty, or inane repetition of class/concept names. Perhaps the authors trust that naming is so good that code will be self-explaining.
Not at all.
Oh, but it almost is! Problem is that the generated docs are less clear than reading the header files. This speaks well for your headers, less so for the docs. Btw, I think I've seen comments on this list to the effect that generated (eg Doxygen) documentation is not good enough for Boost libraries; good documentation must be designed in itself.
In addition to the design guide and tutorial, we have Doxygen documentation for every public interface and lots of private ones. Which part of the code you feel is not well documented?
The ones where the comment just repeats the class or concept name. Eg, the full documentation for MutablePixelIteratorAdaptorConcept reads: "Pixel iterator adaptor that is mutable." Actually I'm suggesting they be removed to save us from skimming repetitions. At the top levels of models and concepts there is hardly any documentation. It might be forgiven that Point, Pixel and Color have brief oneliners, but see Channel: "Concept for channel and mutable channel." Most users getting this far will know what it is, but having the word "color" somewhere on the page would not be affrontery would it? Even if we know what the "usual" meaning is, the syntax supported in this library could be outlined. Interaction with other concepts might be mentioned, there and then. Two or three levels down in the doc tree occasional substantial information appears. This is the reverse from what I expect. Bottom-up design should not result in bottom-up documentation. And the oneliners are offputting. After clicking ten links and finding one or two pages with more info than the link text, I had to decide whether to click *all* links, or give up. I went for the header files. This is a friendly turn mind you, I think many potential end users wouldn't.
Links in the tutorial point to places that don't help understanding at all, whereas the places where something substantial is said are buried 2-4 links away from the TOC of reference docs. (Eg class image_view. I posted about this a while ago.)
Rasmus - these links are automatically generated by Doxygen, which might explain why some of them may not feel logically placed. We could look into suppressing some of these links that don't make sense. Thanks for the suggestion.
Of course - just put a % sign before a name to suppress the link. But I'm not asking for suppresion here, I'm asking for more links, to places of interest in the context. Oh, did I forget to say thanks? Dash, where are my manners... Sorry. Thanks for GIL and for putting it through the Boost review! Regards, rasmus

Rasmus Ekman wrote:
The worries I try to express are: (1) Will the design work out in the long run? - GIL is not proven yet.
Rasmus Ekman wrote:
we want to see GIL used extensively and make sure the fundamentals are absolutely solid
Exactly. Can I say it now? Me too!
Design, documentation, broad domain, code quality - these are all valid criteria for a successful boost submission. But does boost require that a library be extensively used by many people before being accepted? How many of the boost libraries have been extensively used and proven in the long run upon their initial acceptance? Can we please have the same criteria used for other boost submissions be used for GIL. That said, GIL is not a toy project. At least one feature in the next generation of Photoshop will use GIL. You can buy today Photoshop Elements and its Photo Organizer mode will let you find human faces in your photographs to help with tagging: http://opensource.adobe.com/gil/facetagging.pdf This is using a very early version of GIL. We have published a CVPR paper on our (GIL-based) face detector and shown that it compares well against the fastest and most accurate published face detectors. GIL has been ported to the camera phone platform. This feature automatically zooms on the people in your picture: http://opensource.adobe.com/gil/facezoom.pdf We have been in contact with other companies that also use GIL. So, having industrial-level applications using GIL is a good endorsement. Of course, that doesn't mean that the GIL design is rock-solid and future changes won't be necessary. As with every library, we expect the GIL code to evolve and get improved over time.
(2) Where is GIL going? - If it is accepted, this gives more or less blank cheque to make additions - or not.
True for every other library. We are pursuing GIL and would like to see it improved, but we cannot promise any specific improvements.
From the download page: "It is in a very early stage of development; it is not documented and has not been optimized for performance."
I'm sure you're partly just being modest here, but I didn't consider downloading it when the review was first announced, then didn't look back until yesterday.
Yes, when we said "not optimized for performance" what we meant to say is that the code does not meet our internal expectations for performance. That doesn't mean it is not fast enough for many real applications. For example, our convolution uses compile-time recursion to avoid the overhead of explicit loop. You may find that some of the well established libraries don't have this.
The ones where the comment just repeats the class or concept name. Eg, the full documentation for MutablePixelIteratorAdaptorConcept reads: "Pixel iterator adaptor that is mutable." Actually I'm suggesting they be removed to save us from skimming repetitions.
Yes, perhaps we should remove the comments for obvious classes.
At the top levels of models and concepts there is hardly any documentation. It might be forgiven that Point, Pixel and Color have brief oneliners, but see Channel: "Concept for channel and mutable channel." Most users getting this far will know what it is, but having the word "color" somewhere on the page would not be affrontery would it?
Yes, we could add a few more sentences in the Doxygen structure to describe the concepts channel, pixel, image, etc. Please note though that a Doxygen structure is not even required for a boost submission. Those concepts you mention are already described in the design guide. And again, let's compare with the other libraries. Granted, GIL is larger than the average boost library, but we provide 40 pages of design guide, 12 pages of tutorial, an hour of video presentation with 150+ slides and a full Doxigen browsing tree. The lines of code of our documentation far exceed the lines of GIL code. That said, your comment is well taken and we will work on improving the documentation and making it more streamlined. Thanks for your input. Lubomir

Design, documentation, broad domain, code quality - these are all valid criteria for a successful boost submission. But does boost require that a library be extensively used by many
Lubomir Bourdev wrote: people before being accepted? How many of the boost libraries have been extensively used and proven in the long run upon their initial acceptance? Can we please have the same criteria used for other boost submissions be used for GIL. Lubomir Bourdev wrote:
And again, let's compare with the other libraries. Granted, GIL is larger than the average boost library, but we provide 40 pages of design guide, 12 pages of tutorial, an hour of video presentation with 150+ slides and a full Doxigen browsing tree.
I just want to clarify to everyone that by these comments I did not in any way mean to suggest that boost libraries are not well documented or not "proven in the long run". I did not say that but my words could easily be misconstrued in this way. We at Adobe have embraced the boost libraries for many projects precisely because we believe they are solid and reliable. We think boost is an excellent initiative and this is why we would like to support this initiative by contributing GIL, and perhaps other future libraries. I apologize if my comparison may have offended anyone. Lubomir

On Fri, Oct 13, 2006 at 01:43:50PM -0700, Lubomir Bourdev wrote:
First of all, as far as we know we don't have a formal proposal from Vigra on the table, so we feel it is unfair to reject for this reason.
See http://lists.boost.org/Archives/boost/2001/11/19803.php
Here is another perhaps more important question to the boost audience: If you have to make a choice, would you choose a library with a better design and a minimal set of existing algorithms or a library that has more stuff in it, but with not so good a design?
This is IMO not a question of either or - both GIL and Vigra have spots where they shine, and areas where they could learn from the other lib.
A related question: Which one is easier - building new functionality on top of a solid design, or extending the design of a library with lots of existing algorithms that are built on top of the old design?
What if you need to revert your design, because certain functionality is not (or not easily) implementable - and you only find out while doing that one, specific algorithm? So, seeing a lib with lots of (algorithmic) functionality kind of increases my confidence that the basic design is sound...
Merging between GIL/Vigra or especially GIL/AGG would be interesting.
To repeat: I'd at least like to have Vigra's concept of pixel accessors and promotion traits merged/applied in GIL. Cheers, -- Thorsten

Thorsten wrote:
On Fri, Oct 13, 2006 at 01:43:50PM -0700, Lubomir Bourdev wrote:
A related question: Which one is easier - building new functionality on top of a solid design, or extending the design of a library with lots of existing algorithms that are built on top of the old design?
What if you need to revert your design, because certain functionality is not (or not easily) implementable - and you only find out while doing that one, specific algorithm? So, seeing a lib with lots of (algorithmic) functionality kind of increases my confidence that the basic design is sound...
Your argument is generally true, but not in the case of GIL. GIL's goal is simple - to provide consistent, fast and representation-independent access to the pixels of an image. I claim that navigating the image and being able to get/set the values of the pixels is sufficient interface to build any imaging algorithm. Can you provide a counterexample?
Merging between GIL/Vigra or especially GIL/AGG would be interesting.
To repeat: I'd at least like to have Vigra's concept of pixel accessors and promotion traits merged/applied in GIL.
Promotion traits, as I stated in another thread, are handy and there is definitely a value in providing them. But I think they are an integral part of the imaging algorithms and therefore belong in the numeric extension. So stay tuned! As for Vigra's pixel accessors... I read the documentation and I am still struggling to understand the difference between using them and using a PixelDereferenceAdaptor. If they indeed serve the same purpose, that would be an argument against including them in GIL. Can you post a simple example that illustrates how pixel accessors in Vigra are used? Thanks, Lubomir

On Sun, Oct 15, 2006 at 12:16:15PM -0700, Lubomir Bourdev wrote:
Thorsten wrote:
On Fri, Oct 13, 2006 at 01:43:50PM -0700, Lubomir Bourdev wrote:
A related question: Which one is easier - building new functionality on top of a solid design, or extending the design of a library with lots of existing algorithms that are built on top of the old design?
What if you need to revert your design, because certain functionality is not (or not easily) implementable - and you only find out while doing that one, specific algorithm? So, seeing a lib with lots of (algorithmic) functionality kind of increases my confidence that the basic design is sound...
Your argument is generally true, but not in the case of GIL.
:-) Well. You've asked a general question, I've responded generally.
As for Vigra's pixel accessors... I read the documentation and I am still struggling to understand the difference between using them and using a PixelDereferenceAdaptor. If they indeed serve the same purpose, that would be an argument against including them in GIL. Can you post a simple example that illustrates how pixel accessors in Vigra are used?
accessor_t src_a, dst_a; iterator_t src_i, dst_i; // copy pixel from src_i to dst_i dst_a.set(src_a(src_i), dst_i); So, there's more to them than just a way to interpose a function object into setting/getting a pixel value (which is what a PixelDereferenceAdaptor does): One can totally customize the interaction between accessor and iterator, thus leaving considerably more leeway to both implementer and compiler, when applying Vigra algorithms (which all employ a stanza like above). Whereas GIL's iterator_t src_i, dst_i; // copy pixel from src_i to dst_i *dst_i = *src_i; glues access and iteration together (N1550's new iterator concepts are there for a reason - STL iterators do mix several aspects). True, there's a way to customize access, by wrapping a value type with e.g. planar_ptr. But that's kind of involved, and buries things that could be right at ones fingertips deep down in the innards of GIL. And to ask the other way 'round: are there any reasons *not* to use the accessor concept? It's for free in all cases you don't need it, makes clear the dichotomy between access and traversal (which is especially apparent for the domain of image pixel), and is used successfully in a state-of-the-art image processing framework. Cheers, -- Thorsten

Can you post a simple example that illustrates how pixel accessors in Vigra are used?
accessor_t src_a, dst_a; iterator_t src_i, dst_i;
// copy pixel from src_i to dst_i dst_a.set(src_a(src_i), dst_i);
So, there's more to them than just a way to interpose a function object into setting/getting a pixel value (which is what a PixelDereferenceAdaptor does):
One can totally customize the interaction between accessor and iterator, thus leaving considerably more leeway to both implementer and compiler, when applying Vigra algorithms (which all employ a stanza like above).
Whereas GIL's
iterator_t src_i, dst_i;
// copy pixel from src_i to dst_i *dst_i = *src_i;
glues access and iteration together (N1550's new iterator concepts are there for a reason - STL iterators do mix several aspects). True, there's a way to customize access, by wrapping a value type with e.g. planar_ptr. But that's kind of involved, and buries things that could be right at ones fingertips deep down in the innards of GIL.
And to ask the other way 'round: are there any reasons *not* to use the accessor concept?
So, to summarize, GIL incorporates the pixel transformation function into the iterator itself, whereas Vigra uses accessor objects separately, and goes through their interface explicitly to get/set the values of pixels, correct? If so, I think accessors are a major limitation. First of all, don't you need to write four versions of each generic algorithm, based on whether the source and destination have accessors or not? Or do you always provide accessors (the default ones doing a noop) and use their set method? Both alternatives are problematic. Second, isn't it cumbersome to provide an accessor separately from the iterator and to have to pass it around everywhere you need it? Third, perhaps the most severe limitation, expressions like "dst_a.set(src_a(src_i),dst_i)" do not follow standard iterator interfaces and cannot be used in any standard generic algorithms. For example, how can you invoke any STL algorithm on images that have custom accessors? Lubomir
It's for free in all cases you don't need it, makes clear the dichotomy between access and traversal (which is especially apparent for the domain of image pixel), and is used successfully in a state-of-the-art image processing framework.
Cheers,
-- Thorsten _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Hi all, Quoting Lubomir Bourdev <lbourdev@adobe.com>:
So, to summarize, GIL incorporates the pixel transformation function into the iterator itself, whereas Vigra uses accessor objects separately, and goes through their interface explicitly to get/set the values of pixels, correct?
If so, I think accessors are a major limitation.
There are two major reasons why I think Data Accessors are a good idea: 1. incorporating pixel transformation functions into the iterator is much more work than writing an accessor because all the navigation functionality is (unnecessarily) repeated. This is not a big deal for a simple forward iterator, but becomes much more involved for complicated iteration patterns such as 2-dimensional navigation. Handling orthogonal concepts (navigation and data access) in separate classes just makes sense to me. 2. more importantly: the STL data access idiom via *iterator has a major limitation in that the (non-const) iterator::operator* must be able to handle rvalue and lvalue semantics simultaneously: value = *iterator; *iterator = value; However, lvalue and rvalue transformations may require very different implementations. For example, consider an RGB pixel in 565 format packed into a 16 bit unsigned int. Suppose you need an iterator adaptor whose operator* just reads/writes the green channel -- implementing this is very tricky and requires a proxy. Similarly, how do you implement "RGBValue & iterator::operator*()" when the color channels are located in different bands? In contrast, implementing either functionality by means of the separate get and set functions of a data accessor is trivial. This was the main motivation for introducing accessors. If the C++ language allowed for separate implementations of the lvalue and rvalue operator*, I'd reconsider the matter.
Or do you always provide accessors (the default ones doing a noop) and use their set method?
That's what we do in VIGRA, and the noops are nicely optimized away by all compilers we tested.
Second, isn't it cumbersome to provide an accessor separately from the iterator and to have to pass it around everywhere you need it?
That's not a big deal. Most of the time, you use the dafault accessor, which is automatically passed to the algorithms by means of an argument object. Admittedly, "dst_a.set(src_a(src_i),dst_i)" is not as nice as "*dest_i = *src_i" in terms of syntax, but it is much more powerful in terms of semantics (see above).
Third, perhaps the most severe limitation, expressions like "dst_a.set(src_a(src_i),dst_i)" do not follow standard iterator interfaces and cannot be used in any standard generic algorithms.
Yes, and I didn't take the decision lightly. But as I said, I consider this a limitation of the STL and the operator* semantics rather than a limitation of VIGRA.
For example, how can you invoke any STL algorithm on images that have custom accessors?
You can invoke them because operator* is always available in any VIGRA iterator. I.e., VIGRA provides the possibility to write GIL-style iterator adaptors. Regards Ulli Koethe (VIGRA maintainer)

Hi Lubomir, on Sun, Oct 15, 2006 at 07:09:44PM -0700, you wrote:
So, to summarize, GIL incorporates the pixel transformation function into the iterator itself, whereas Vigra uses accessor objects separately, and goes through their interface explicitly to get/set the values of pixels, correct?
If by 'pixel transformation' you mean all the magic that's needed to access the pixel's internal memory representation, then yes.
First of all, don't you need to write four versions of each generic algorithm, based on whether the source and destination have accessors or not? Or do you always provide accessors (the default ones doing a noop) and use their set method? Both alternatives are problematic.
Not an issue (of course there are default noop accessors for STL-like iterators). Why do you think this is problematic?
Second, isn't it cumbersome to provide an accessor separately from the iterator and to have to pass it around everywhere you need it?
Iterators and accessors can be passed as tuples - typically a triple <i_begin,i_end,acc> for the source and a pair <i_begin,acc> for the destination image. But that should be obvious from the Vigra docs...
Third, perhaps the most severe limitation, expressions like "dst_a.set(src_a(src_i),dst_i)" do not follow standard iterator interfaces and cannot be used in any standard generic algorithms. For example, how can you invoke any STL algorithm on images that have custom accessors?
Well, you wrote in B55F4112A7B48C44AF51E442990015C0016F3A56@namail1.corp.adobe.com
But GIL doesn't use any of these. It uses performance specializations as follows: 1. If both images are interleaved and have no padding at the end of rows, invokes a single memmove 2. If both images are planar and have no padding at the end of rows, invokes a memmove for each channel 3. If they are of the same type but have padding at the end of rows, invokes memmove for each row (or K-memmoves per row in the case of K-channel planar images)
Thus, you're specializing for certain iterator types anyway - no difference compared to Vigra. In fact, you would probably specialize all those types that have non-trivial accessors in Vigra - simply because there's so much room for optimization (take a fill on a 1bpp image, for example - no need to execute that bit-by-bit, no? Or a paletted destination image - you probably won't fill it by repeated palette lookup for a constant color value and every single pixel). Being able to employ stl algorithms for those types is a theoretical advantage at best. For all the other iterators types provided by Vigra, stl algos work like a charm. Lubomir, I really don't want to be a nag, and I'm getting the impression that this discussion is leading nowhere. I just wanted to point out what I perceived superior in Vigra - at the end of the day, it's prolly a minor issue, at least if the set of pixel iterators is complete for common formats (1-N packed pixel, palette lookup, 16bit floats). Still, I'd love to see a best-of-both-worlds solution (a merge of Vigra and GIL functionality - since Vigra was also offered to boost some time ago...). But then again, that's probably off-topic and certainly none of my business in this review thread. Cheers, -- Thorsten

Hi Thorsten,
Lubomir, I really don't want to be a nag, and I'm getting the impression that this discussion is leading nowhere.
I will reply to the other parts of your post separately, but I am puzzled by this paragraph. I thought our discussion is going very well - we are exploring the benefits and drawbacks of using accessors vs pixel dereference adaptors. This discussion has been very valuable for me and I hope for other people following the list, so lets keep doing it. We are both using logical arguments and code to illustrate our points. I call this a very constructive discussion. A discussion that is based on subjective arguments would be going nowhere, but I thought this is not the case here. Please don't take it personally! And yes, email is a horrible means of communication... ;-) Lubomir

Hi all, since VIGRA has been mentioned several times in the discussion of GIL, I (as the VIGRA maintainer) would like to add a few comments. Some people on the list perhaps remember that I offered VIGRA for inclusion into boost a few years ago (must have been around 2002). Back then, it didn't find much acceptance, so I didn't push very far. Due to the renewed interest in image libraries, I'd like to repeat my offer now -- I still think that boost would be a good home for VIGRA. I also consider some integration with GIL an option, although one has to check what is technically possible and can be done by volunteers. In any case, I like GIL's extensive use of the view concept. On Fri, Oct 13, 2006 at 01:43:50PM -0700, Lubomir Bourdev wrote:
A related question: Which one is easier - building new functionality on top of a solid design, or extending the design of a library with lots of existing algorithms that are built on top of the old design?
This implies that functionality (i.e. algorithms) should be build on top of a solid (i.e. more or less finalized) design. However, in my experience this is impossible: as one tries to implement new functionality, one constantly meets limitations of the original design. It is the hallmark of good design that it can be adapted to these evolving needs with minimal effort. VIGRA has proven to be very flexible in this respect: we added much new functionality to the VIGRA core with hardly ever breaking backwards compatibility in existing algorithms. A design can only be really judged by demonstrating that it can evolve according to the needs of new requirements. In the GIL design guide, VIGRA is explicitely criticised for lack of two features: 1. support for different channel orderings such as BGR and conversions between them. This feature has been added to VIGRA about a year ago. 2. support for images with separate channels: VIGRA handles them by means of 3-dimensional MultiArray and MultiArrayView templates. The only things missing are DataAccessors that interprete these as 2-dimenional structures with multiband pixels, and interfaces to the older BasicImage/BasicImageView group of 2D image classes and algorithms. Both can be added trivially when there is sufficient demand (which has been lacking so far). Someone else pointed out that VIGRA provides an interface to the FFTW library whose license is incompatible with the boost license. This is true, but the FFTW can be replaced with another FFT library without much work provided that the new library is not restricted to power-of-2 image sizes (and it should prefarably be based on std::complex). Regards Ulli Koethe (VIGRA maintainer)

On 10/16/06, koethe@informatik.uni-hamburg.de < koethe@informatik.uni-hamburg.de> wrote:
Due to the renewed interest in image libraries, I'd like to repeat my offer now -- I still think that boost would be a good home for VIGRA. I also consider some integration with GIL an option, although one has to check what is technically possible and can be done by volunteers. In any case, I like GIL's extensive use of the view concept.
It would be great news if the GIL authors and yourself can manage to integrate both libraries. I haven't sent my GIL review, but while GIL provides a sound design it would benefit most by combining with the more mature VIGRA library. I believe that GIL without a broad set of imaging algorithms is not very useful (although there is an expectation that many will contribute algorithms, I don't think it is realistic !). On the other hand, you provide a broad set of algorithm implementations (not just image processing) that have been available for several years (and that have improved the design of the core imaging libray) One approach, assuming GIL authors cooperation, would be to add what's missing to GIL (as you discuss in other messages) and then have a common unique image container library that the algorithms can be ported to. thank you for offering the VIGRA library !

Jose wrote:
It would be great news if the GIL authors and yourself can manage to integrate both libraries.
I haven't sent my GIL review, but while GIL provides a sound design it would benefit most by combining with the more mature VIGRA library.
We would be happy to see GIL's image abstraction combined with VIGRA's algorithms. That would be the best of both worlds! However, what we don't want to see is the review of GIL postponed to the indefinite future or the current GIL submission rejected because of the lack of VIGRA's algorithms. GIL core is a library with a very specific goal - to provide efficient and representation-independent access to the pixels of an image. Providing an extensive set of image processing algorithms has never been the design goal of GIL core. While no library can ever be complete, we believe GIL provides a comprehensive solution to the stated goal. Here is why we believe GIL is ready for boost submission as-is: 1. The set of image algorithms is fundamentally open-ended. Vigra has a good set of them, but so do other libraries, like Intel's IPP, and ITK. Why stop with VIGRA, why not take advantage of all of them? And why stop at imaging algorithms; why not include computer vision algorithms like the ones in OpenCV? And why not add vector graphics algorithms, like the ones in AGG and Cairo? And when would we be ever done? 2. A library with multiple goals that could logically and easily be separated should be broken down into multiple libraries. Notably, image processing algorithms (like the ones in VIGRA) constitute a separate goal and deserve a separate library. Vector graphics (AGG) is another separate goal and deserves a separate library. Of course, it makes sense for both of them to make heavy use of a core library (like GIL) that abstracts away the image representation. 3. As Matt Gruenke states, the goal that GIL addresses is sufficiently important in itself to justify it constituting a separate submission. There are many cases where you deal with images in which you don't need to deal with image processing algorithms. By providing GIL in boost today, we will address the needs of this set of people that would otherwise have to wait for an unspecified amount of time for something they don't need. 4. GIL is a large library. Adding an extensive set of algorithms to it will make it really huge. This will put a big burden on the boost review process and it will be hard to ensure high quality for a very large library. We believe it is better for boost to consume large libraries as a set of smaller, solid and self-contained component libraries. 5. One argument I heard mentioned is, before writing lots of algorithms, how do you know that your core is solid? It seems more appropriate to start with algorithms and derive the data structures from them. While we think this is generally the right approach, we are confident that GIL can handle any imaging algorithm. This is because all GIL does is provide an efficient and representation-independent access to the pixels of an image, and this is all you need to be able to write any imaging algorithm. We have certainly provided a proof of concept by providing fully generic algorithms for convolution, resampling and generating the gradient. We are not saying that the core is complete, in a sense that it provides you with all the tools you need in designing image processing algorithms. In writing GIL image processing algorithms you may discover useful abstractions, like, for example, the need for promotion traits. Some of these abstractions may logically remain in the numeric extension, but the best place for others may be GIL core. So adding imaging algorithms will likely be associated with updating the core with some new functionality, and maybe some minimal interface changes, and this is a natural evolution for any library. However, we don't believe that big changes to the current interfaces and large redesign of GIL core will be necessary. Some people say that GIL is a new library, so its design is unproven in the long run. While GIL has a shorter life compared to mature libraries like Vigra, we have been working on GIL for more than three years, designing, implementing, throwing away and redesigning it from scratch many times until we reach a design that we are confident with. In designing GIL we have examined and taken advantage of the ideas behind many mature imaging libraries, including Vigra. We have also drawn from the expertise of many people at Adobe, and imaging is one of Adobe's core businesses. Finally, we are using GIL to solve real problems. Lubomir & Hailin

On 10/16/06, Lubomir Bourdev <lbourdev@adobe.com> wrote:
However, what we don't want to see is the review of GIL postponed to the indefinite future or the current GIL submission rejected because of the lack of VIGRA's algorithms.
Has anybody implied this ? GIL core is a library with a very specific goal - to provide efficient
and representation-independent access to the pixels of an image. Providing an extensive set of image processing algorithms has never been the design goal of GIL core. While no library can ever be complete, we believe GIL provides a comprehensive solution to the stated goal.
My point of view is of the library user, not the library developer, and I am asking for a library users can use without having to develop established algorithms. Would STL be useful without STL algorithms ? I know GIL does provide basic algorithms but I am arguing about image-specific algorithms which you've started to provide in the numerics extension 1. The set of image algorithms is fundamentally open-ended. Vigra has a
good set of them, but so do other libraries, like Intel's IPP, and ITK. Why stop with VIGRA, why not take advantage of all of them? And why stop at imaging algorithms; why not include computer vision algorithms like the ones in OpenCV? And why not add vector graphics algorithms, like the ones in AGG and Cairo? And when would we be ever done?
That's fine but no excuse for providing the basic ones in GIL. There's also a huge set of algorithms/structures not in STL (tries, TST, b-trees, ..) but STL has the most common ones. I hope the analogy with STL helps get the point across ! 2. A library with multiple goals that could logically and easily be
separated should be broken down into multiple libraries. Notably, image processing algorithms (like the ones in VIGRA) constitute a separate goal and deserve a separate library. Vector graphics (AGG) is another separate goal and deserves a separate library. Of course, it makes sense for both of them to make heavy use of a core library (like GIL) that abstracts away the image representation.
The only goal that matters is that the library is used. I think a few reviewers/comments hit on the point that GIL has only the container, iterators and very basic algorithms (but this is changing with the numerics extension) 3. As Matt Gruenke states, the goal that GIL addresses is sufficiently
important in itself to justify it constituting a separate submission. There are many cases where you deal with images in which you don't need to deal with image processing algorithms.
To be specific, which cases are you referring to and how useful/important are ? I mean end user cases. If I were a library developer then GIL might be pretty useful as it is right now to build my own library on top of it. By providing GIL in boost
today, we will address the needs of this set of people that would otherwise have to wait for an unspecified amount of time for something they don't need.
But the VIGRA author also pointed out that as they were developing new algorithms the core design evolved/changed 4. GIL is a large library. Adding an extensive set of algorithms to it
will make it really huge. This will put a big burden on the boost review process and it will be hard to ensure high quality for a very large library. We believe it is better for boost to consume large libraries as a set of smaller, solid and self-contained component libraries.
Sorry to be blunt but it looks like you're searching for excuses ! I am not trying to jiggle the review. The review is great as it is but many times the library is accepted and some libraries don't continue to evolve as they should (not blaming anybody but just suggesting this should be considered in the review) 5. One argument I heard mentioned is, before writing lots of algorithms,
how do you know that your core is solid? It seems more appropriate to start with algorithms and derive the data structures from them. While we think this is generally the right approach, we are confident that GIL can handle any imaging algorithm. This is because all GIL does is provide an efficient and representation-independent access to the pixels of an image, and this is all you need to be able to write any imaging algorithm. We have certainly provided a proof of concept by providing fully generic algorithms for convolution, resampling and generating the gradient.
Confidence is good but results/data is better :-) We are not saying that the core is complete, in a sense that it provides
you with all the tools you need in designing image processing algorithms.
Well, then we're agreeing! In writing GIL image processing algorithms you may discover
useful abstractions, like, for example, the need for promotion traits.
Let me state first that I am no expert but I read the book Applied C++ - Stroustrup C++ In-Depth Series, which uses as an example for the whole book the design of an image library. One of the basic things is what they call campling (== promotion traits ?) In page 29 (memory allocation) they mention "We needed such a function inside our image processing functions to control the behaviour in overflow and underflow conditions. Specialized versions of this function test for overflow and clamp the output value at the maximum value for that data type ... " The fact that GIL doesn't provide campling makes me argue it is not a mature library. It's such a basic need (I get this from reading the book!) None of the above should be interpreted as criticism. My only wish is that the imaging library that is included in boost is as good as it can be. Also, I've not praised many of the good aspects of GIL as these have been pointed out already.

On 10/17/06, Jose <jmalv04@gmail.com> wrote:
One of the basic things is what they call campling (== promotion traits ?)
Are you referring to what is commonly called "clamping"? If yes, I don't think this is what promotion traits are for (but maybe my definition of the latter is off). Regards, Michael

On 10/17/06, Michael Walter <michael.walter@gmail.com> wrote:
On 10/17/06, Jose <jmalv04@gmail.com> wrote:
One of the basic things is what they call campling (== promotion traits ?)
Are you referring to what is commonly called "clamping"? If yes, I don't think this is what promotion traits are for (but maybe my definition of the latter is off).
I stated that I am not an expert so I hope this gets explained by the experts. Actually I only now about clamping as per the mentioned C++ book but I have not looked at promotion traits (but I inferred from the messages that promotion traits handle the overflow/underflow cases)

Michael Walter wrote:
One of the basic things is what they call campling (== promotion traits ?)
Are you referring to what is commonly called "clamping"? If yes, I don't think this is what promotion traits are for (but maybe my definition of the latter is off).
Clamping is one functionality provided by promotion traits in VIGRA. Our promotion traits not only define which types should result from mixed-type expressions, but also how the values are transformed (this can be further customized by means of data accessors). Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

The fact that GIL doesn't provide campling makes me argue it is not a mature library. It's such a basic need (I get this from reading the book!)
To clamp a channel in GIL you can just say: T channel; T clamped = std::min(channel, channel_max_value<T>()); We actually had a set of primitive channel-level algorithms that also included clamp, but we decided to remove things you can do with a simple one-line expression so we don't clutter the interface. Lubomir

Lubomir Bourdev wrote:
The fact that GIL doesn't provide campling makes me argue it is not a mature library. It's such a basic need (I get this from reading the book!)
To clamp a channel in GIL you can just say:
T channel; T clamped = std::min(channel, channel_max_value<T>());
But that's not how things work in practice. When the data are already stored as type T, overflow has already occured. Moreover, the possibility of overflow typically arises deep inside some algorithm, where you cannot simply call std::min(), but need another mechanism (e.g. promotion traits). Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

Hi Ullrich and Jose -- GIL has something similar to promotion traits in the numeric extension. Moreover, it is designed so that users can easily override the default behaviors without sacrificing performance. More specificly, the algorithms in the numeric extension allow users to specify types for holding intermediate results. The intermediate types are then passed into a set of pre-defined structs for doing fundamental numerical operations such as addition, subtraction, etc (see extension/numeric/pixel_numeric_operations.hpp). All the structs are templated over input types (one, two or more) and output types, which are often the intermediate types, and these structs are consistently used throughout the numeric extension. As a result, the user can specify either "float" or "double" as the intermediate type for convoluting a "unsigned char" image with a "float" kernel. Hailin Ullrich Koethe wrote:
Lubomir Bourdev wrote:
The fact that GIL doesn't provide campling makes me argue it is not a mature library. It's such a basic need (I get this
from reading the book!)
To clamp a channel in GIL you can just say:
T channel; T clamped = std::min(channel, channel_max_value<T>());
But that's not how things work in practice. When the data are already stored as type T, overflow has already occured. Moreover, the possibility of overflow typically arises deep inside some algorithm, where you cannot simply call std::min(), but need another mechanism (e.g. promotion traits).
Ulli

It would be great news if the GIL authors and yourself can manage to integrate both libraries.
Regarding incorporating Vigra algorithms into GIL's numeric extension: We think this is a great idea, and we would be happy to collaborate with Vigra and make it easier for them to put their algorithms into the numeric extension, and to have a joint future boost submission of the image-processing extension, with Vigra and perhaps other interested parties. If Vigra's contribution is significant, we would be happy to have Vigra take the lead role in providing the imaging algorithms to boost. Similarly, we would be happy to collaborate with AGG into providing vector graphics support into a boost submission. We encourage Prof. Köthe and any other people familiar with Vigra to take part of GIL's review as we feel their experience is very valuable. Lubomir

Quoting Lubomir Bourdev <lbourdev@adobe.com>:
Promotion traits, as I stated in another thread, are handy and there is definitely a value in providing them. But I think they are an integral part of the imaging algorithms and therefore belong in the numeric extension. So stay tuned!
I my experience promotion traits are absolutely necessary to implement genereric image processing algorithms. Consider the simple matter of adding two or more byte images. In order to avoid overflow, intermediate results should be stored in a short or an int. If the result is to be written back to a byte image, the destination accessor can take care of shifting the result back into the appropriate range or clipping at the range limits. Promotion traits control this behavior. Hardly any algorithm in VIGRA can do without them. Regards Ulli

I my experience promotion traits are absolutely necessary to implement genereric image processing algorithms.
Since I didn't watch this thread closely I don't know if you're talking about recent addition to boost.type_traits (http://lists.boost.org/boost-announce/2006/04/0084.php) or something completely different. My guess is that you use different version of promotion traits in VIGRA. Is it correct? PS, I know one other implementation, adobe::promote: http://opensource.adobe.com/structadobe_1_1promote.html -- Alexander Nasonov

Alexander Nasonov wrote:
I my experience promotion traits are absolutely necessary to implement genereric image processing algorithms.
Since I didn't watch this thread closely I don't know if you're talking about recent addition to boost.type_traits (http://lists.boost.org/boost-announce/2006/04/0084.php) or something completely different. My guess is that you use different version of promotion traits in VIGRA. Is it correct?
Yes. Originally, I learned the concept from the blitz++ library. Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

I my experience promotion traits are absolutely necessary to implement genereric image processing algorithms. Consider the simple matter of adding two or more byte images. In order to avoid overflow, intermediate results should be stored in a short or an int. If the result is to be written back to a byte image, the destination accessor can take care of shifting the result back into the appropriate range or clipping at the range limits. Promotion traits control this behavior. Hardly any algorithm in VIGRA can do without them.
Regards Ulli
Ulli: We don't believe the type of the result could automatically be inferred simply from the types of arguments. The optimal type depends on your intent and the context. For example, VIGRA's promotion traits choose double as the promotion for int when dealing with floating point operations. Why not float? On many architectures float is faster, and precision may not be an issue in the context in which you use it. Why should int always be the result type of adding two ints? Depending on what you are doing int may overflow... Int for summing two shorts will not overflow, but what if you are building, say, the integral image and you want to sum the values of all pixels in your image? As you can see, the optimal type depends on a complex interaction between speed, capacity and desired precision and hard-coding it makes the algorithms less generic. This is why in GIL we allow the type of the result to be specified explicitly upon invoking the operation. Promotion traits can at best be useful for a reasonable default, but even then we feel that they belong in boost::type_traits and not in an image library, as the problem generalizes beyond images. Lubomir

Hi Lubomir, Lubomir Bourdev wrote:
We don't believe the type of the result could automatically be inferred simply from the types of arguments. The optimal type depends on your intent and the context.
True. But the result type is usually not automatically inferred in VIGRA (it is inferred from the destination image you passed in). Promote traits are mainly used for the definition of intermediate types (e.g. temporary images). Essentially, promotion traits make explicit what the compiler is doing anyway. For example, the type of an expression adding two signed chars is always int, regardless of the type of the variable the result is ultimately assigned to. We wanted to achieve the same for the addition of images. (We did not always get it right, but this can be corrected.)
For example, VIGRA's promotion traits choose double as the promotion for int when dealing with floating point operations. Why not float? On many architectures float is faster, and precision may not be an issue in the context in which you use it.
Right, some customization would be nice. But the defaults have worked very well for us most of the time, so we didn't feel an urgent need to change the behavior.
Why should int always be the result type of adding two ints?
Because that's what the C++ standard says (AFAIR).
Int for summing two shorts will not overflow, but what if you are building, say, the integral image and you want to sum the values of all pixels in your image?
This can be handled by means of an appropriate Inspector with value_type double or BigInt. The VIGRA Inspector concept is like a Functor, except that it doesn't return a value, but collects some statistics about the values it has seen. (Note that VIGRA is also defined in terms of concepts, although not quite as nice as GIL.)
This is why in GIL we allow the type of the result to be specified explicitly upon invoking the operation. Promotion traits can at best be useful for a reasonable default,
Resonable defaults are everything in generic programming, otherwise it's unusable.
We feel that promotion traits belong in boost::type_traits and not in an image library, as the problem generalizes beyond images.
I agree. Regards Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

Ullrich Koethe wrote:
For example, VIGRA's promotion traits choose double as the promotion for int when dealing with floating point operations. Why not float? On many architectures float is faster, and precision may not be an issue in the context in which you use it.
Why should int always be the result type of adding two ints?
Because that's what the C++ standard says (AFAIR).
But the standard isn't always the best answer for all promotion situations. For example, some years back I wrote some expression template code for simulation purposes. I wanted a simple user interface so I promoted int / int to double to avoid loss of precision. Stuffed away in some cobweb-infested dusty disk sector I have a library that implements promotion "strategies" using a table-driven configuration of (operator/operand type -> promotion type) rules. I'll see if I can dig it out and post it as a starting point. I'm not sure if it's what we want as a Boost library but it might be a start for discussion. -Dave

Hi David, David Greene wrote:
Because that's what the C++ standard says (AFAIR).
But the standard isn't always the best answer for all promotion situations. For example, some years back I wrote some expression template code for simulation purposes. I wanted a simple user interface so I promoted int / int to double to avoid loss of precision.
Right. So VIGRA supports two promotions standard Promote (what the compiler does by default) and RealPromote (the floating point promotion is guaruanteed)
Stuffed away in some cobweb-infested dusty disk sector I have a library that implements promotion "strategies" using a table-driven configuration of (operator/operand type -> promotion type) rules.
That's how VIGRA's promotion traits essentially work.
I'll see if I can dig it out and post it as a starting point. I'm not sure if it's what we want as a Boost library but it might be a start for discussion.
Will be interesting to look at. Regards Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

"Lubomir Bourdev" <lbourdev@adobe.com> wrote in message news:B55F4112A7B48C44AF51E442990015C00173AFC1@namail1.corp.adobe.com...
We don't believe the type of the result could automatically be inferred simply from the types of arguments.
The type of the result is fixed by the types of the arguments, therefore, simply ... the type of the result is automatically inferred simply from the types of arguments. The optimal type depends on your
intent and the context.
The type of the result is fixed by the types of the arguments.
For example, VIGRA's promotion traits choose double as the promotion for int when dealing with floating point operations. Why not float? On many architectures float is faster, and precision may not be an issue in the context in which you use it.
Why should int always be the result type of adding two ints? Depending on what you are doing int may overflow... Int for summing two shorts will not overflow, but what if you are building, say, the integral image and you want to sum the values of all pixels in your image?
As you can see, the optimal type depends on a complex interaction between speed, capacity and desired precision and hard-coding it makes the algorithms less generic.
So, I'm guessing that GIL doesnt support UDT's? regards Andy Little

We don't believe the type of the result could automatically be inferred simply from the types of arguments.
The type of the result is fixed by the types of the arguments, therefore, simply ... the type of the result is automatically inferred simply from the types of arguments.
What I meant to say is that the OPTIMAL type cannot be inferred automatically from the types of arguments. It depends on the many criteria I listed. Lubomir

Lubomir Bourdev wrote:
This is why in GIL we allow the type of the result to be specified explicitly upon invoking the operation. Promotion traits can at best be useful for a reasonable default, but even then we feel that they belong in boost::type_traits and not in an image library, as the problem generalizes beyond images.
I agree. I am not quite fond of monolithic libraries that do everything. Promotion traits and clamping, for example, can also be useful for, say, signal processing of audio, among other things. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Joel de Guzman wrote:
Lubomir Bourdev wrote:
This is why in GIL we allow the type of the result to be specified explicitly upon invoking the operation. Promotion traits can at best be useful for a reasonable default, but even then we feel that they belong in boost::type_traits and not in an image library, as the problem generalizes beyond images.
I agree. I am not quite fond of monolithic libraries that do everything. Promotion traits and clamping, for example, can also be useful for, say, signal processing of audio, among other things.
True. But on the other hand, one has to control the number of external dependencies -- if a potential user must install 5 or 10 other libraries first, he might quickly loose interest. In image processing, one wants at least libjpeg, libtiff, libpng (which in turn requires zlib), perhaps a fourier transform library, possibly boost, a linear algebra library (for warping and curve fitting), a GUI library (which often already comes with incompatible image import/export functionality) and so on -- there is certainly a trade-off between internal and external solutions. Of course, there are platforms where installation is easy, but you want to be general. Regards Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

This might OT for this particular thread, so feel free to ignore my question. But it might be topical for Boost.Build and installing Boost in general, so I'm asking :-) Ullrich Koethe wrote:
Of course, there are platforms where installation is easy, but you want to be general.
I only know of one platform where that is true, but essentially no one uses it any more. Which are you referring to? And what makes them "easy"? -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - grafikrobot/yahoo

Rene Rivera wrote:
This might OT for this particular thread, so feel free to ignore my question. But it might be topical for Boost.Build and installing Boost in general, so I'm asking :-)
Ullrich Koethe wrote:
Of course, there are platforms where installation is easy, but you want to be general.
I only know of one platform where that is true, but essentially no one uses it any more. Which are you referring to? And what makes them "easy"?
Well, I should have said "relatively easy". I specifically refered to platforms were binary installation is possible and can be expected to work correctly with reasonable probability (some Linux variants?), as opposed to platforms were all packages (including dependencies) must be compiled from the sources (certainly all traditional Unixes, and Windows when a particular configuration or compiler build is not available in binary form). For what it's worth: VIGRA tries to provide basic functionality in a number of areas simply to get you started (e.g. it can natively import/export Windows BMP and a few other image formats, it has a simple lambda library, basic linear algebra functions), but allows the ambitious to use more sophisticated libraries when necessary (e.g. boost::lambda). Ulli -- ________________________________________________________________ | | | Ullrich Koethe Universitaet Hamburg / University of Hamburg | | FB Informatik / Dept. of Informatics | | AB Kognitive Systeme / Cognitive Systems Group | | | | Phone: +49 (0)40 42883-2573 Vogt-Koelln-Str. 30 | | Fax: +49 (0)40 42883-2572 D - 22527 Hamburg | | Email: u.koethe@computer.org Germany | | koethe@informatik.uni-hamburg.de | | WWW: http://kogs-www.informatik.uni-hamburg.de/~koethe/ | |________________________________________________________________|

Rene Rivera said: (by the date of Tue, 17 Oct 2006 21:06:22 -0500)
Ullrich Koethe wrote:
Of course, there are platforms where installation is easy, but you want to be general.
I only know of one platform where that is true, but essentially no one uses it any more. Which are you referring to? And what makes them "easy"?
On debian-based linux distributions you just type sudo aptitude install libpng and you are done. I call this an easy install :) -- Janek Kozicki |

Ullrich Koethe wrote:
Joel de Guzman wrote:
Lubomir Bourdev wrote:
This is why in GIL we allow the type of the result to be specified explicitly upon invoking the operation. Promotion traits can at best be useful for a reasonable default, but even then we feel that they belong in boost::type_traits and not in an image library, as the problem generalizes beyond images.
I agree. I am not quite fond of monolithic libraries that do everything. Promotion traits and clamping, for example, can also be useful for, say, signal processing of audio, among other things.
True. But on the other hand, one has to control the number of external dependencies -- if a potential user must install 5 or 10 other libraries first, he might quickly loose interest.
In image processing, one wants at least libjpeg, libtiff, libpng (which in turn requires zlib), perhaps a fourier transform library, possibly boost, a linear algebra library (for warping and curve fitting), a GUI library (which often already comes with incompatible image import/export functionality) and so on -- there is certainly a trade-off between internal and external solutions. Of course, there are platforms where installation is easy, but you want to be general.
Isn't this a problem of packaging instead of monolithic vs. modular libraries? IMO, the level of granularity of a library reflects its design. A well factored library, as a result of extensive refactoring, over time, results in small highly orthogonal, loosely coupled sub- libraries. A monolithic library, on the other hand, tend to devolve into chaos over time. Don't get me wrong. I am not referring to VIGRA; I am not familiar with it and its design. I am just talking in general terms. And, referring back to GIL, I see that it hits the exact sweet spot in terms of modularity. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

So far, the three rejections I've seen all cite GIL's scope as a major/primary fault. Interestingly, the desired scope of each reviewer is different and possibly incompatible with the others: one desires a higher-level and far more general approach, one desires additional functionality, and one desires further decomposition. So, I'm beginning to wonder whether consensus on this matter is actually possible. I'd like to use some points made in this particular review to offer my understanding of GIL's scope, and my case that it encompasses a problem worthy of a solution in the form of a Boost library. I will provide my own review, separately. rasmus ekman wrote:
I vote that GIL is rejected this time.
This is not because I doubt the usefulness or quality of implementation, more due to the fact that there is at least one other generic library (Vigra), which covers much of the same field, that has been around longer, and supplies many more algorithms.
Since this seems to be the primary reason for your rejection of GIL, I'm curious whether your concern is that: a) it doesn't solve enough problems to be useful or b) it doesn't solve as many problems as it could My take on 'a' is that GIL absolutely does address problems concerning those who endeavor to write graphics and image processing routines that aren't tied to a specific image representation. If you're not interested in this problem, why do you use that as a basis for rejecting the library? Imagine you were writing fairly generic image manipulation routines - wouldn't you like a unified and efficient interface for accessing images of various precision and layout? 'b' is fundamentally open-ended and applies to a great number of libraries and problem domains. As it doesn't directly relate to the value of a solution, I think it doesn't warrant further discussion. I believe the core questions should be whether it solves a worth-while problem, and whether it does this in a way that meets Boost standards.
Vigra provides interface to FFTW, filters and convolution.
FYI, the FFTW library is fundamentally incompatible with boost's license requirements. For commercial applications, FFTW makes it non-free, and thus not directly comparable. Of course, you can compile it without FFTW support. Anyhow, I see GIL as an image access library - not an image algorithms library. My case for simply having a good solution to the image access problem follows. Suppose an algorithm provided by a given library didn't meet your requirements for speed, precision, supported image formats, or memory footprint. Perhaps you don't want to drag in a whole new library, just for one or two algorithms. Maybe you have a novel algorithm or implementation approach. For whatever reason, you can't or don't want to use the implementation provided by an existing library. In practice, these issues are quite common. Such cases would be less likely, if the library were written on top of a GIL-style image model. However, even if GIL did include a collection of algorithms - and had the very one you wanted - there's no guarantee that it would make an optimal or even acceptable performance vs. accuracy tradeoff, for your needs. When you're stuck writing your own implementation, it's helpful to have some routines that facilitate efficient image access. It'd be even better, if you could subsequently revisit decisions about your image representation, or reuse the same code for different types of images. For these reasons, even those who are simply consumers of image synthesis, manipulation, and transformation algorithms should see some value in GIL and the problem it solves. In summary, generic image access is instrumental in facilitating generic image algorithms. Since even the most generic and comprehensive collection of image algorithms will not suit all needs and uses, it's important to have a fallback solution for efficient & flexible image access. As you can see by the amount of work that went into GIL, this is not an easy problem to solve. IMO, it can and should be solved independently from the implementation of algorithms that use it. Matt Gruenke

Matt, If it's okay with you, your post doesn't seem to require a detailed response from me. I've made some comments, positive and negative, well-founded or misguided, and any rehashing of them just adds noise to the workload of the review manager. (IIUC he's the impartial party who will weigh various points, the willingness of library authors to change, or motivations not to, and synthesize a collective judgement. I'm under the impression we don't need to argue every millimeter, just clarify the points sufficiently for him to record them. For this reason I also underscored the limitations of my review and the underlying perspective.) So, your task is not to sway me. Outvote me instead. After seeing the numeric_examples code posted the other day I'm rather hoping this happens, but I interpreted it that the extension is not part of the submission. See also http://boost.org/more/formal_review_process.htm#Submitters - though it doesn't explicitly cover this case. Other boosters and the rev.mgr hopefully know how to judge these things, including the progress made over the last few weeks (my impression is that GIL was just a little rushed to review). Cheers, re

I vote for GIL to be accepted into boost. Design ====== GIL provides a very powerful representation of Pixels, Images, and related concepts. They are very generic, yet allow highly efficient code to be written. The models fall into two categories: pixel-related (channels, color-space, etc.), and pixel-container-related (image, locator, iterator, etc.). I believe the pixel-model is very well done. I asked for a special-case representation of packed heterogeneous pixels (such as rgb565), and Lubomir demonstrated how to provide such pixel types using the existing concepts. While the pixel-container part is quite good, I believe it can be refined a bit: * It should be possible to create row-major, as well as column-major images, to speed up column-based algorithms. As pixels have 'channels' as well as 'semantic channels', images may have 'rows' as well as 'semantic rows'. * It may be worthwhile generalizing some of the API in parametrizing dimensions (for example to have a 'size(axis)' method instead of 'width()' / 'height()', or having a stride(axis) method returning the step size along rows and columns... Implementation ============== I think the implementation is very clean. I have only some minor points: * The io extensions should use iostream instead of stdio (i.e. std::iostreams instead of FILE *) * Variable names should not start with an underscore, as such names are reserved. * The implementation should be extended to provide unit tests (many of them !). (A little anecdote: I tried to assign an image A to an image B with A and B of different types. The code didn't compile since the copy constructor attempts to access A's private member _alloc. This is a fairly simple case that would have been detected easily had there been a unit test for it.) Documentation ============= I think the existing documentation is very good. The presentation certainly helps a lot ! I think it would be very helpful to add sections to the tutorial that describe how to introduce custom pixel and image (well, locator) types. That would demonstrate the reasoning behind lots of the chosen concepts. The library should contain example programs to demonstrate all the individual aspects of the library. Applicability ============= I believe the library is extremely useful in its domain. Thus far it mostly provides types and some 'core' algorithms. I'm certain that, once accepted, implementations for all the common image processing algorithms will emerge quickly. Evaluation ========== My evaluation is based on my reading (and listening to) the documentation, as well as using GIL to write some sample applets. I have used the new packed pixel types, combined GILs pixel types with my own Matrix types (VSIPL++), etc. I used g++ 4.1.1. While I wouldn't call me an expert in the problem domain, I think I am sufficiently knowledgeable to judge GIL's usefulness. Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin...

Stefan, Thanks for your support! Stefan Seefeld wrote:
I vote for GIL to be accepted into boost.
Design ======
* It should be possible to create row-major, as well as column-major images, to speed up column-based algorithms. As pixels have 'channels' as well as 'semantic channels', images may have 'rows' as well as 'semantic rows'.
Can't you just use transposed_view ?
* It may be worthwhile generalizing some of the API in parametrizing dimensions (for example to have a 'size(axis)' method instead of 'width()' / 'height()', or having
"get_dimensions(view)[n]" returns the size along n-th dimension If your dimensions have different types, you could use: get_dimensions(view).template axis_value<N>();
a stride(axis) method returning the step size along rows and columns...
The step in bytes is only applicable to memory-based image views. For those, you could say: "view.pixels().row_bytes()" for byte-step in y "view.pixels().pix_bytestep()" for byte-step in x For a generic N-dimensional memory-based image you could use the more generic accessors: "byte_step(view.template axis_iterator<N>())"
Implementation ==============
I think the implementation is very clean. I have only some minor points:
* The io extensions should use iostream instead of stdio (i.e. std::iostreams instead of FILE *)
Good point.
* Variable names should not start with an underscore, as such names are reserved.
We will change this if there is a strong consensus. But there are other boost libraries that do that.
I think it would be very helpful to add sections to the tutorial that describe how to introduce custom pixel and image (well, locator) types. That would demonstrate the reasoning behind lots of the chosen concepts.
Doesn't the Mandelbrot set example show how to introduce new locator/image types? As for custom pixels, perhaps even better is to make packed pixels part of GIL. Once this is done, making custom pixel types would be needed very rarely if at all...
The library should contain example programs to demonstrate all the individual aspects of the library.
You mean code snippets? Thanks for your review! Lubomir

Lubomir, Lubomir Bourdev wrote:
Stefan Seefeld wrote:
* It should be possible to create row-major, as well as column-major images, to speed up column-based algorithms. As pixels have 'channels' as well as 'semantic channels', images may have 'rows' as well as 'semantic rows'.
Can't you just use transposed_view ?
As you point out in your presentation, an y-gradient can be implemented by combining a transpose with an x-gradient. However, due to all the cache misses performance will suffer terribly. Therefor, if I know that I'm going to run a number of column-wise operations (FFT's come to mind), I may want to corner-turn my image first. I know I can do this explicitely, but sometimes it is good to push this into the type, and the transpose into the type-conversion. This has better potential for optimization.
* It may be worthwhile generalizing some of the API in parametrizing dimensions (for example to have a 'size(axis)' method instead of 'width()' / 'height()', or having
"get_dimensions(view)[n]" returns the size along n-th dimension
If your dimensions have different types, you could use: get_dimensions(view).template axis_value<N>();
I see. Sorry I missed that !
a stride(axis) method returning the step size along rows and columns...
The step in bytes is only applicable to memory-based image views. For those, you could say:
"view.pixels().row_bytes()" for byte-step in y "view.pixels().pix_bytestep()" for byte-step in x
For a generic N-dimensional memory-based image you could use the more generic accessors:
"byte_step(view.template axis_iterator<N>())"
OK.
Implementation ==============
[...]
I think it would be very helpful to add sections to the tutorial that describe how to introduce custom pixel and image (well, locator) types. That would demonstrate the reasoning behind lots of the chosen concepts.
Doesn't the Mandelbrot set example show how to introduce new locator/image types?
Right. That's very useful ! But I think there should be more such examples, notably to show how to bind existing code / types to GIL types.
As for custom pixels, perhaps even better is to make packed pixels part of GIL. Once this is done, making custom pixel types would be needed very rarely if at all...
Right, and I agree packed pixels should become part of GIL core. However, this argument isn't what I'm arguing for. :-) My point is that showing how to write custom pixel types is an excellent device to explain the design. I think I understand the relevant part of GIL much better now simply because I was interested into how to write a (5,6,5) Pixel type to be binary-compatible with IPP. (I could have picked an arbitrary other type, this was really just a way to get my feed wet.)
The library should contain example programs to demonstrate all the individual aspects of the library.
You mean code snippets?
Code snippets would be good, but complete minimal programs would be even better. What a better way to demonstrate an algorithm than by showing how it transforms an input image into an output image. Thanks, Stefan -- ...ich hab' noch einen Koffer in Berlin...

Hi Here's my GIL review:
Please always explicitly state in your review, whether you think the library should be accepted into Boost.
I vote to accept GIL into boost. As part of my review, I wrote an AGG (http://www.antigrain.com/) renderer using GIL. You can get the code here: http://spirit.sourceforge.net/dl_more/gil/gil.zip You will need the latest AGG library (v2.4). For the test, I opted not to use any library other than AGG, GIL and of course Boost. The test writes a PPM file which can be read by most image utilities. IrfanView (http://www.irfanview.com/) is a popular and free image software. I added a pre-compiled app for Windows users in the package. It's interesting to note that the entire thing (app) is just 60K. This includes the entire vertex source for the image hard-coded. This reflects the modularity of GIL and AGG and the resulting code is very tight. Both GIL and AGG are highly modular, generic libraries. You pay only for features that you do not need. Here's the output of the test: http://spirit.sourceforge.net/dl_more/gil/lion.png gil_renderer.hpp is an AGG renderer for GIL views and images. AGG has a flexible pipeline architecture: Vertex Source | Coordinate conversion pipeline | Scanline Rasterizer | Renderers | Rendering Buffer | Screen output By plugging into the renderer layer, I am able to make AGG work with the full suite of GIL views and images, including those that AGG does not support directly such as planar images, CMYK, LAB color-spaces etc. By replacing the Renderers and Rendering Buffer, AGG can be greatly simplified. And, as a result, make it even more flexible. GIL provides more functionality at that level. AGGs real forte is in the upper half of the library whle GIL's focus is in the lower half. The gil_renderer class I provided is bare bones. To take full advantage of AGG (and GIL), a lot more functions need to be written. For the purpose of the review, I also hard-coded the blending of anti-aliased scan lines to RGB. It's certainly possible to make it fully generic for all color spaces as discussed in the GIL tutorial.
- What is your evaluation of the design?
A+. I like libraries that are tight and highly focused. GIL is one of those. I see that a lot of effort has been invested on design. There's one issue that was discussed: that of pixel accessors. It was argued that VIGRA's data accessors provide more flexibility than GIL's use of plain iterators and iterator adapters. There may be some truth in that. This is very similar to the Cursor/Property Map Abstraction that Dave Abrahams and Dietmar Kühl advocate. (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1873.html). I invite the GIL authors to investigate this angle. Yet, I see no reason to reject GIL for their design choice whichever way they choose. It's their call. I recall facing the same choice before with Fusion. I chose the plain iterator approach. Yet, Dave did not reject the library when Fusion was finally reviewed. I'd like to see Fusion integration with GIL. I suggested, off-list, that GIL color-spaces can and should be Fusion sequences. In particular, they can be thought of as fusion associative sequences (http://tinyurl.com/ymhl9q). With fusion integration, GIL does not have to reinvent algorithms for heterogeneous types such as GIL's pixel algorithms (e.g. for_each_channel, generate_channels and tranform_channels). Surely, this is not enough, and Fusion has a lot more (http://tinyurl.com/ym6n75). A use case that I presented is a more intuitive gradient_on_luminance algorithm, which applies the halfdiff_cast_channel function only on channels that affect luminance. For HSV, it can selectively work on only V, in HSL, L, in YUV, Y, in RGB, CMYK, all channels. Pixels are n-tuples. GIL pixel algorithms work on these tuples. It seems a lot like a work better suited for the Fusion library. Consider this snippet: fusion::transform( fusion::filter<has_luminance<mpl::_1> >(a) , fusion::filter<has_luminance<mpl::_1> >(b) , halfdiff_cast_channel<C>()); which reads: apply halfdiff_cast_channel only on channels that has luminance information; ignoring hue information. The end result is still color with graduated brightness/luminance. Hence, the result over RGB and HSL will be similar, for example. Also, operations on fusion sequences (Again, I think color spaces should be fully conforming fusion sequences) is darned fast. It does the same compile time recursion you mentioned in GIL docs, albeit more extensively and more generically (i.e. not just on pixels but on all hetero-sequences in general). It will be fast because no conversion ever takes place (not even a copy).
- What is your evaluation of the implementation?
B+. I thought I'd give some negative marks here because I was not able to see any regression tests, but Lubomir quickly pointed out that there are some in the ASL repository. Indeed there are tests. However, I give this a B+ because the tests are not extensive and do not cover a lot. I see only 6 tests. A lot more work should be invested in this area. I also notice that GIL does not follow Boost conventions. I expected something like this directory structure: + boost + gil + libs + gil + test + doc + example I expect the authors to follow this convention if/when GIL is accepted.
- What is your evaluation of the documentation?
B-. I enjoyed the tutorial and the Design guide a lot. The Breeze presentation is a first in boost. It is entertaining and insightful. Like other people, I too noticed some rough edges and inconsistencies. For example, the author at the start of the presentation says "if you don't know about STL iterators, think of them like pointers". (or something to that effect). Then later, he shows of some MPL and Lambda snippets without hesitation. I think the author is not consistent with the way he thinks of his target audience. Is this for newbies with no knowledge of STL iterators or for advanced folks with MPL/Lambda background? Make up your mind. Be consistent. In any case, a brief bakgrounder into MPL and Lambda would be in order. The doxygen documentation, I have to be blunt, was not useful to me at all. I ended up reading header files which were more informative. Let's take an example: http://opensource.adobe.com/gil/html/group___channel.html IMO, this page is totally useless. Example: Detailed Description: Channel and channel operations. C'mon, you can do better than that! Your docs do not do justice to your otherwise elegant design! I'd say rework the docs from scratch with more care and attention and love :)
- What is your evaluation of the potential usefulness of the library?
Oh man, do I have to answer this? :-)
- Did you try to use the library? With what compiler? Did you have any problems?
Yes, I invested a full weekend learning about the library. Well, actually I had to learn 2 libraries (AGG and GIL). I am not an expert with AGG at all. I was just a mere lurker in the AGG mailing list until the past weekend.
- How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
In depth. I studied the code in full. Read the docs cover top cover. Wrote an adaptor from AGG to GIL. I invested the entire weekend on this.
- Are you knowledgeable about the problem domain?
I can't say I am an expert on this domain. I did have my share of blitting and stuff, though, especially in the early years. I've written at least 2 GUI frameworks from scratch. The first one was pre Windows. I was inspired by GUIs and wrote one for DOS machines. I did the blitters and the graphics engine in assembly and pascal. One of the apps was a paint program where we designed our UI graphics. The second was a refinement of the first, this time in C++, inspired by fresco, minus the fat :). Then, I also did lots of low-level graphics stuff because the graphics library we had, at the time, was very poor: Mac's QuickDraw. Also, I wanted to do cross-platform and the PC's GDI was also very poor. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net

Hi Joel, Thanks for the time you spent reviewing GIL and for your vote! The AGG integration example is certainly very interesting, and we will add it to the list of GIL example files. Thanks for doing all this proof-of-concept work! The Fusion integration is a neat idea and I see no immediate obstacles to doing this. The less code in GIL, the better :-) Let's discuss details off-line.
- What is your evaluation of the implementation?
B+. I thought I'd give some negative marks here because I was not able to see any regression tests, but Lubomir quickly pointed out that there are some in the ASL repository. Indeed there are tests. However, I give this a B+ because the tests are not extensive and do not cover a lot. I see only 6 tests. A lot more work should be invested in this area.
I am not sure if you found the regression tests. Our regression suite is fairly extensive, though the code is not very well organized and we don't test all aspects systematically. I found it _really_ hard to have comprehensive testing generic components, especially of this size. But we cover images and image views, including planar and interleaved, gray and RGB, images with channel permutations (BGR vs RGB), subsampled, color_converted views, and piping them with all possible view transformations (rotation, nth_channel, etc). We run this with both memory-based and synthetic images (the mandelbrot set). We invoke the histogram and the gradient algorithm, also some STL algorithms, reverse iterators, etc. Running our tests generates 98 image files that result in applying various combinations of the algorithms and image views. Our regression code compares each of these with reference images and throws an exception if there are differences. We also have some compile-time tests that use concept checks. We also have some basic performance tests, which consist of comparing GIL loops with hand-written C loops, but the tests are very rudimentary and not very thorough.
I also notice that GIL does not follow Boost conventions. I expected something like this directory structure:
+ boost + gil + libs + gil + test + doc + example
I expect the authors to follow this convention if/when GIL is accepted.
Of course!
- What is your evaluation of the documentation?
B-. I enjoyed the tutorial and the Design guide a lot. The Breeze presentation is a first in boost. It is entertaining and insightful. Like other people, I too noticed some rough edges and inconsistencies. For example, the author at the start of the presentation says "if you don't know about STL iterators, think of them like pointers". (or something to that effect). Then later, he shows of some MPL and Lambda snippets without hesitation. I think the author is not consistent with the way he thinks of his target audience. Is this for newbies with no knowledge of STL iterators or for advanced folks with MPL/Lambda background? Make up your mind. Be consistent.
yes, good point!
In any case, a brief bakgrounder into MPL and Lambda would be in order.
The doxygen documentation, I have to be blunt, was not useful to me at all. I ended up reading header files which were more informative. Let's take an example:
http://opensource.adobe.com/gil/html/group___channel.html
IMO, this page is totally useless. Example:
Detailed Description:
Channel and channel operations.
C'mon, you can do better than that! Your docs do not do justice to your otherwise elegant design! I'd say rework the docs from scratch with more care and attention and love :)
I feel that if we hadn't provided Doxygen documentation at all we would have gotten higher reviews on documentation :-) The Doxygen documentation is not even required part of the submission, so it comes extra... Those concepts are described better in the design guide.
- What is your evaluation of the potential usefulness of the library?
Oh man, do I have to answer this? :-)
Well, a few people like Jose and Rasmus were not quite convinced, so a straight answer would be nice, though you implied one. Thanks again for the extensive work you put in this review! Lubomir

Lubomir Bourdev wrote:
Hi Joel,
Thanks for the time you spent reviewing GIL and for your vote!
The AGG integration example is certainly very interesting, and we will add it to the list of GIL example files. Thanks for doing all this proof-of-concept work!
The Fusion integration is a neat idea and I see no immediate obstacles to doing this. The less code in GIL, the better :-) Let's discuss details off-line.
Definitely! I'd be glad to help.
- What is your evaluation of the implementation? B+. I thought I'd give some negative marks here because I was not able to see any regression tests, but Lubomir quickly pointed out that there are some in the ASL repository. Indeed there are tests. However, I give this a B+ because the tests are not extensive and do not cover a lot. I see only 6 tests. A lot more work should be invested in this area.
I am not sure if you found the regression tests.
Our regression suite is fairly extensive, though the code is not very [...]
I see. Oh, pardon me then. Can you guys make that public and easily accessible? I don't think I am the only one who looks at regression tests first and foremost? Regressions plus examples speak volumes! If only GIL was presented in the canonical boost directory structure, then, this wouldn't have been a problem. I suggest that future review managers require this prior to review to avoid any confusion. Anyway, I stick to the grade because (I forgot to mention) the lack of examples too. To me, examples by themselves, speak volumes.
I feel that if we hadn't provided Doxygen documentation at all we would have gotten higher reviews on documentation :-) The Doxygen documentation is not even required part of the submission, so it comes extra...
I disagree. The reference docs is a crucial part of the docs, as do concept docs and tutorials. I know. I've been criticized in the past for that (i.e. spirit). Hence, with Fusion comes extensive STL style reference docs. That too has not been without criticisms. Documentation is an art that I am still trying to learn.
Those concepts are described better in the design guide.
- What is your evaluation of the potential usefulness of the library?
Oh man, do I have to answer this? :-)
Well, a few people like Jose and Rasmus were not quite convinced, so a straight answer would be nice, though you implied one.
Hmmm... Ok, for the record: I find GIL to be a very useful library. I like its modularity among all its traits. GILs granularity and modularity hits a sweet spot that makes it extremely useful for integration with other libraries and even, I dare to say, as a core of many graphics libraries. It is extremely flexible, extensible and adaptable. As far as the design and implementation of the library goes, it's A+. No doubt about that. And to me, that's what matters most. All the talk about comparing GIL to other libraries is constructive, to say the least, but should not be a factor for rejecting the library. IMO. There's some precedent already in boost where multiple overlapping libraries were accepted (i.e. regex, xpressive and spirit).
Thanks again for the extensive work you put in this review!
Most welcome! I enjoyed GIL. Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net
participants (18)
-
Alexander Nasonov
-
Andy Little
-
David Greene
-
Hailin Jin
-
Janek Kozicki
-
Joel de Guzman
-
Jose
-
koethe@informatik.uni-hamburg.de
-
Lubomir Bourdev
-
Matt Gruenke
-
Michael Walter
-
rasmus ekman
-
Rene Rivera
-
Stefan Seefeld
-
Thorsten
-
Thorsten Behrens
-
Tom Brinkman
-
Ullrich Koethe