Squashed 'external/CImg/' content from commit c0becdf8

git-subtree-dir: external/CImg
git-subtree-split: c0becdf881b0f3e2445975cac01c2422170d1fd9
This commit is contained in:
Leon Styhre 2021-06-07 22:08:20 +02:00
commit 3b12410b91
353 changed files with 235549 additions and 0 deletions

20
.travis.yml Normal file
View file

@ -0,0 +1,20 @@
language: cpp
compiler:
- gcc
script:
- cd examples
- make CXX='g++-4.8' travis
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
- g++-4.8
- clang
- libpng12-dev
- libjpeg-dev
- libmagick++-dev
- libgraphicsmagick++1-dev
- libfftw3-dev
- zlib1g-dev

64793
CImg.h Normal file

File diff suppressed because it is too large Load diff

508
Licence_CeCILL-C_V1-en.txt Normal file
View file

@ -0,0 +1,508 @@
CeCILL-C FREE SOFTWARE LICENSE AGREEMENT
Notice
This Agreement is a Free Software license agreement that is the result
of discussions between its authors in order to ensure compliance with
the two main principles guiding its drafting:
* firstly, compliance with the principles governing the distribution
of Free Software: access to source code, broad rights granted to
users,
* secondly, the election of a governing law, French law, with which
it is conformant, both as regards the law of torts and
intellectual property law, and the protection that it offers to
both authors and holders of the economic rights over software.
The authors of the CeCILL-C (for Ce[a] C[nrs] I[nria] L[logiciel] L[ibre])
license are:
Commissariat à l'Energie Atomique - CEA, a public scientific, technical
and industrial research establishment, having its principal place of
business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
Centre National de la Recherche Scientifique - CNRS, a public scientific
and technological establishment, having its principal place of business
at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
Institut National de Recherche en Informatique et en Automatique -
INRIA, a public scientific and technological establishment, having its
principal place of business at Domaine de Voluceau, Rocquencourt, BP
105, 78153 Le Chesnay cedex, France.
Preamble
The purpose of this Free Software license agreement is to grant users the
right to modify and re-use the software governed by this license.
The exercising of this right is conditional on the obligation to make
available to the community the modifications made to the source code of the
software so as to contribute to its evolution.
In consideration of access to the source code and the rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors only have limited liability.
In this respect, the risks associated with loading, using, modifying
and/or developing or reproducing the software by the user are brought to
the user's attention, given its Free Software status, which may make it
complicated to use, with the result that its use is reserved for
developers and experienced professionals having in-depth computer
knowledge. Users are therefore encouraged to load and test the suitability
of the software as regards their requirements in conditions enabling the
security of their systems and/or data to be ensured and, more generally, to
use and operate it in the same conditions of security. This Agreement may be
freely reproduced and published, provided it is not altered, and that no
provisions are either added or removed herefrom.
This Agreement may apply to any or all software for which the holder of
the economic rights decides to submit the use thereof to its provisions.
Article 1 - DEFINITIONS
For the purpose of this Agreement, when the following expressions
commence with a capital letter, they shall have the following meaning:
Agreement: means this license agreement, and its possible subsequent
versions and annexes.
Software: means the software in its Object Code and/or Source Code form
and, where applicable, its documentation, "as is" when the Licensee
accepts the Agreement.
Initial Software: means the Software in its Source Code and possibly its
Object Code form and, where applicable, its documentation, "as is" when
it is first distributed under the terms and conditions of the Agreement.
Modified Software: means the Software modified by at least one Integrated
Contribution.
Source Code: means all the Software's instructions and program lines to
which access is required so as to modify the Software.
Object Code: means the binary files originating from the compilation of
the Source Code.
Holder: means the holder(s) of the economic rights over the Initial
Software.
Licensee: means the Software user(s) having accepted the Agreement.
Contributor: means a Licensee having made at least one Integrated
Contribution.
Licensor: means the Holder, or any other individual or legal entity, who
distributes the Software under the Agreement.
Integrated Contribution: means any or all modifications, corrections,
translations, adaptations and/or new functions integrated into the Source
Code by any or all Contributors.
Related Module: means a set of sources files including their documentation
that, without modification to the Source Code, enables supplementary
functions or services in addition to those offered by the Software.
Derivative Software: means any combination of the Software, modified or not,
and of a Related Module.
Parties: mean both the Licensee and the Licensor.
These expressions may be used both in singular and plural form.
Article 2 - PURPOSE
The purpose of the Agreement is the grant by the Licensor to the
Licensee of a non-exclusive, transferable and worldwide license for the
Software as set forth in Article 5 hereinafter for the whole term of the
protection granted by the rights over said Software.
Article 3 - ACCEPTANCE
3.1 The Licensee shall be deemed as having accepted the terms and
conditions of this Agreement upon the occurrence of the first of the
following events:
* (i) loading the Software by any or all means, notably, by
downloading from a remote server, or by loading from a physical
medium;
* (ii) the first time the Licensee exercises any of the rights
granted hereunder.
3.2 One copy of the Agreement, containing a notice relating to the
characteristics of the Software, to the limited warranty, and to the
fact that its use is restricted to experienced users has been provided
to the Licensee prior to its acceptance as set forth in Article 3.1
hereinabove, and the Licensee hereby acknowledges that it has read and
understood it.
Article 4 - EFFECTIVE DATE AND TERM
4.1 EFFECTIVE DATE
The Agreement shall become effective on the date when it is accepted by
the Licensee as set forth in Article 3.1.
4.2 TERM
The Agreement shall remain in force for the entire legal term of
protection of the economic rights over the Software.
Article 5 - SCOPE OF RIGHTS GRANTED
The Licensor hereby grants to the Licensee, who accepts, the following
rights over the Software for any or all use, and for the term of the
Agreement, on the basis of the terms and conditions set forth hereinafter.
Besides, if the Licensor owns or comes to own one or more patents
protecting all or part of the functions of the Software or of its
components, the Licensor undertakes not to enforce the rights granted by
these patents against successive Licensees using, exploiting or
modifying the Software. If these patents are transferred, the Licensor
undertakes to have the transferees subscribe to the obligations set
forth in this paragraph.
5.1 RIGHT OF USE
The Licensee is authorized to use the Software, without any limitation
as to its fields of application, with it being hereinafter specified
that this comprises:
1. permanent or temporary reproduction of all or part of the Software
by any or all means and in any or all form.
2. loading, displaying, running, or storing the Software on any or
all medium.
3. entitlement to observe, study or test its operation so as to
determine the ideas and principles behind any or all constituent
elements of said Software. This shall apply when the Licensee
carries out any or all loading, displaying, running, transmission
or storage operation as regards the Software, that it is entitled
to carry out hereunder.
5.2 RIGHT OF MODIFICATION
The right of modification includes the right to translate, adapt, arrange,
or make any or all modifications to the Software, and the right to
reproduce the resulting Software. It includes, in particular, the right
to create a Derivative Software.
The Licensee is authorized to make any or all modification to the
Software provided that it includes an explicit notice that it is the
author of said modification and indicates the date of the creation thereof.
5.3 RIGHT OF DISTRIBUTION
In particular, the right of distribution includes the right to publish,
transmit and communicate the Software to the general public on any or
all medium, and by any or all means, and the right to market, either in
consideration of a fee, or free of charge, one or more copies of the
Software by any means.
The Licensee is further authorized to distribute copies of the modified
or unmodified Software to third parties according to the terms and
conditions set forth hereinafter.
5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
The Licensee is authorized to distribute true copies of the Software in
Source Code or Object Code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's
warranty and liability as set forth in Articles 8 and 9,
and that, in the event that only the Object Code of the Software is
redistributed, the Licensee allows effective access to the full Source Code
of the Software at a minimum during the entire period of its distribution
of the Software, it being understood that the additional cost of acquiring
the Source Code shall not exceed the cost of transferring the data.
5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
When the Licensee makes an Integrated Contribution to the Software, the terms
and conditions for the distribution of the resulting Modified Software become
subject to all the provisions of this Agreement.
The Licensee is authorized to distribute the Modified Software, in source
code or object code form, provided that said distribution complies with all
the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's warranty and
liability as set forth in Articles 8 and 9,
and that, in the event that only the object code of the Modified Software is
redistributed, the Licensee allows effective access to the full source code
of the Modified Software at a minimum during the entire period of its
distribution of the Modified Software, it being understood that the
additional cost of acquiring the source code shall not exceed the cost of
transferring the data.
5.3.3 DISTRIBUTION OF DERIVATIVE SOFTWARE
When the Licensee creates Derivative Software, this Derivative Software may
be distributed under a license agreement other than this Agreement, subject
to compliance with the requirement to include a notice concerning the rights
over the Software as defined in Article 6.4. In the event the creation of the
Derivative Software required modification of the Source Code, the Licensee
undertakes that:
1. the resulting Modified Software will be governed by this Agreement,
2. the Integrated Contributions in the resulting Modified Software will be
clearly identified and documented,
3. the Licensee will allow effective access to the source code of the
Modified Software, at a minimum during the entire period of
distribution of the Derivative Software, such that such modifications
may be carried over in a subsequent version of the Software; it being
understood that the additional cost of purchasing the source code of
the Modified Software shall not exceed the cost of transferring the
data.
5.3.4 COMPATIBILITY WITH THE CeCILL LICENSE
When a Modified Software contains an Integrated Contribution subject to the
CeCill license agreement, or when a Derivative Software contains a Related
Module subject to the CeCill license agreement, the provisions set forth in
the third item of Article 6.4 are optional.
Article 6 - INTELLECTUAL PROPERTY
6.1 OVER THE INITIAL SOFTWARE
The Holder owns the economic rights over the Initial Software. Any or
all use of the Initial Software is subject to compliance with the terms
and conditions under which the Holder has elected to distribute its work
and no one shall be entitled to modify the terms and conditions for the
distribution of said Initial Software.
The Holder undertakes that the Initial Software will remain ruled at
least by the current license, for the duration set forth in Article 4.2.
6.2 OVER THE INTEGRATED CONTRIBUTIONS
A Licensee who develops an Integrated Contribution is the owner of the
intellectual property rights over this Contribution as defined by
applicable law.
6.3 OVER THE RELATED MODULES
A Licensee who develops an Related Module is the owner of the
intellectual property rights over this Related Module as defined by
applicable law and is free to choose the type of agreement that shall
govern its distribution under the conditions defined in Article 5.3.3.
6.4 NOTICE OF RIGHTS
The Licensee expressly undertakes:
1. not to remove, or modify, in any manner, the intellectual property
notices attached to the Software;
2. to reproduce said notices, in an identical manner, in the copies
of the Software modified or not;
3. to ensure that use of the Software, its intellectual property
notices and the fact that it is governed by the Agreement is
indicated in a text that is easily accessible, specifically from
the interface of any Derivative Software.
The Licensee undertakes not to directly or indirectly infringe the
intellectual property rights of the Holder and/or Contributors on the
Software and to take, where applicable, vis-à-vis its staff, any and all
measures required to ensure respect of said intellectual property rights
of the Holder and/or Contributors.
Article 7 - RELATED SERVICES
7.1 Under no circumstances shall the Agreement oblige the Licensor to
provide technical assistance or maintenance services for the Software.
However, the Licensor is entitled to offer this type of services. The
terms and conditions of such technical assistance, and/or such
maintenance, shall be set forth in a separate instrument. Only the
Licensor offering said maintenance and/or technical assistance services
shall incur liability therefor.
7.2 Similarly, any Licensor is entitled to offer to its licensees, under
its sole responsibility, a warranty, that shall only be binding upon
itself, for the redistribution of the Software and/or the Modified
Software, under terms and conditions that it is free to decide. Said
warranty, and the financial terms and conditions of its application,
shall be subject of a separate instrument executed between the Licensor
and the Licensee.
Article 8 - LIABILITY
8.1 Subject to the provisions of Article 8.2, the Licensee shall be
entitled to claim compensation for any direct loss it may have suffered
from the Software as a result of a fault on the part of the relevant
Licensor, subject to providing evidence thereof.
8.2 The Licensor's liability is limited to the commitments made under
this Agreement and shall not be incurred as a result of in particular:
(i) loss due the Licensee's total or partial failure to fulfill its
obligations, (ii) direct or consequential loss that is suffered by the
Licensee due to the use or performance of the Software, and (iii) more
generally, any consequential loss. In particular the Parties expressly
agree that any or all pecuniary or business loss (i.e. loss of data,
loss of profits, operating loss, loss of customers or orders,
opportunity cost, any disturbance to business activities) or any or all
legal proceedings instituted against the Licensee by a third party,
shall constitute consequential loss and shall not provide entitlement to
any or all compensation from the Licensor.
Article 9 - WARRANTY
9.1 The Licensee acknowledges that the scientific and technical
state-of-the-art when the Software was distributed did not enable all
possible uses to be tested and verified, nor for the presence of
possible defects to be detected. In this respect, the Licensee's
attention has been drawn to the risks associated with loading, using,
modifying and/or developing and reproducing the Software which are
reserved for experienced users.
The Licensee shall be responsible for verifying, by any or all means,
the suitability of the product for its requirements, its good working order,
and for ensuring that it shall not cause damage to either persons or
properties.
9.2 The Licensor hereby represents, in good faith, that it is entitled
to grant all the rights over the Software (including in particular the
rights set forth in Article 5).
9.3 The Licensee acknowledges that the Software is supplied "as is" by
the Licensor without any other express or tacit warranty, other than
that provided for in Article 9.2 and, in particular, without any warranty
as to its commercial value, its secured, safe, innovative or relevant
nature.
Specifically, the Licensor does not warrant that the Software is free
from any error, that it will operate without interruption, that it will
be compatible with the Licensee's own equipment and software
configuration, nor that it will meet the Licensee's requirements.
9.4 The Licensor does not either expressly or tacitly warrant that the
Software does not infringe any third party intellectual property right
relating to a patent, software or any other property right. Therefore,
the Licensor disclaims any and all liability towards the Licensee
arising out of any or all proceedings for infringement that may be
instituted in respect of the use, modification and redistribution of the
Software. Nevertheless, should such proceedings be instituted against
the Licensee, the Licensor shall provide it with technical and legal
assistance for its defense. Such technical and legal assistance shall be
decided on a case-by-case basis between the relevant Licensor and the
Licensee pursuant to a memorandum of understanding. The Licensor
disclaims any and all liability as regards the Licensee's use of the
name of the Software. No warranty is given as regards the existence of
prior rights over the name of the Software or as regards the existence
of a trademark.
Article 10 - TERMINATION
10.1 In the event of a breach by the Licensee of its obligations
hereunder, the Licensor may automatically terminate this Agreement
thirty (30) days after notice has been sent to the Licensee and has
remained ineffective.
10.2 A Licensee whose Agreement is terminated shall no longer be
authorized to use, modify or distribute the Software. However, any
licenses that it may have granted prior to termination of the Agreement
shall remain valid subject to their having been granted in compliance
with the terms and conditions hereof.
Article 11 - MISCELLANEOUS
11.1 EXCUSABLE EVENTS
Neither Party shall be liable for any or all delay, or failure to
perform the Agreement, that may be attributable to an event of force
majeure, an act of God or an outside cause, such as defective
functioning or interruptions of the electricity or telecommunications
networks, network paralysis following a virus attack, intervention by
government authorities, natural disasters, water damage, earthquakes,
fire, explosions, strikes and labor unrest, war, etc.
11.2 Any failure by either Party, on one or more occasions, to invoke
one or more of the provisions hereof, shall under no circumstances be
interpreted as being a waiver by the interested Party of its right to
invoke said provision(s) subsequently.
11.3 The Agreement cancels and replaces any or all previous agreements,
whether written or oral, between the Parties and having the same
purpose, and constitutes the entirety of the agreement between said
Parties concerning said purpose. No supplement or modification to the
terms and conditions hereof shall be effective as between the Parties
unless it is made in writing and signed by their duly authorized
representatives.
11.4 In the event that one or more of the provisions hereof were to
conflict with a current or future applicable act or legislative text,
said act or legislative text shall prevail, and the Parties shall make
the necessary amendments so as to comply with said act or legislative
text. All other provisions shall remain effective. Similarly, invalidity
of a provision of the Agreement, for any reason whatsoever, shall not
cause the Agreement as a whole to be invalid.
11.5 LANGUAGE
The Agreement is drafted in both French and English and both versions
are deemed authentic.
Article 12 - NEW VERSIONS OF THE AGREEMENT
12.1 Any person is authorized to duplicate and distribute copies of this
Agreement.
12.2 So as to ensure coherence, the wording of this Agreement is
protected and may only be modified by the authors of the License, who
reserve the right to periodically publish updates or new versions of the
Agreement, each with a separate number. These subsequent versions may
address new issues encountered by Free Software.
12.3 Any Software distributed under a given version of the Agreement
may only be subsequently distributed under the same version of the
Agreement or a subsequent version.
Article 13 - GOVERNING LAW AND JURISDICTION
13.1 The Agreement is governed by French law. The Parties agree to
endeavor to seek an amicable solution to any disagreements or disputes
that may arise during the performance of the Agreement.
13.2 Failing an amicable solution within two (2) months as from their
occurrence, and unless emergency proceedings are necessary, the
disagreements or disputes shall be referred to the Paris Courts having
jurisdiction, by the more diligent Party.
Version 1.0 dated 2006-07-12.

504
Licence_CeCILL_V2-en.txt Normal file
View file

@ -0,0 +1,504 @@
CeCILL FREE SOFTWARE LICENSE AGREEMENT
Notice
This Agreement is a Free Software license agreement that is the result
of discussions between its authors in order to ensure compliance with
the two main principles guiding its drafting:
* firstly, compliance with the principles governing the distribution
of Free Software: access to source code, broad rights granted to
users,
* secondly, the election of a governing law, French law, with which
it is conformant, both as regards the law of torts and
intellectual property law, and the protection that it offers to
both authors and holders of the economic rights over software.
The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[logiciel] L[ibre])
license are:
Commissariat à l'Energie Atomique - CEA, a public scientific, technical
and industrial research establishment, having its principal place of
business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France.
Centre National de la Recherche Scientifique - CNRS, a public scientific
and technological research establishment, having its principal place of
business at 3 rue Michel-Ange, 75794 Paris cedex 16, France.
Institut National de Recherche en Informatique et en Automatique -
INRIA, a public scientific and technological establishment, having its
principal place of business at Domaine de Voluceau, Rocquencourt, BP
105, 78153 Le Chesnay cedex, France.
Preamble
The purpose of this Free Software license agreement is to grant users
the right to modify and redistribute the software governed by this
license within the framework of an open source distribution model.
The exercising of these rights is conditional upon certain obligations
for users so as to preserve this status for all subsequent redistributions.
In consideration of access to the source code and the rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors only have limited liability.
In this respect, the risks associated with loading, using, modifying
and/or developing or reproducing the software by the user are brought to
the user's attention, given its Free Software status, which may make it
complicated to use, with the result that its use is reserved for
developers and experienced professionals having in-depth computer
knowledge. Users are therefore encouraged to load and test the suitability
of the software as regards their requirements in conditions enabling
the security of their systems and/or data to be ensured and, more
generally, to use and operate it in the same conditions of security.
This Agreement may be freely reproduced and published, provided it is not
altered, and that no provisions are either added or removed herefrom.
This Agreement may apply to any or all software for which the holder of
the economic rights decides to submit the use thereof to its provisions.
Article 1 - DEFINITIONS
For the purpose of this Agreement, when the following expressions
commence with a capital letter, they shall have the following meaning:
Agreement: means this license agreement, and its possible subsequent
versions and annexes.
Software: means the software in its Object Code and/or Source Code form
and, where applicable, its documentation, "as is" when the Licensee
accepts the Agreement.
Initial Software: means the Software in its Source Code and possibly its
Object Code form and, where applicable, its documentation, "as is" when
it is first distributed under the terms and conditions of the Agreement.
Modified Software: means the Software modified by at least one
Contribution.
Source Code: means all the Software's instructions and program lines to
which access is required so as to modify the Software.
Object Code: means the binary files originating from the compilation of
the Source Code.
Holder: means the holder(s) of the economic rights over the Initial
Software.
Licensee: means the Software user(s) having accepted the Agreement.
Contributor: means a Licensee having made at least one Contribution.
Licensor: means the Holder, or any other individual or legal entity, who
distributes the Software under the Agreement.
Contribution: means any or all modifications, corrections, translations,
adaptations and/or new functions integrated into the Software by any or
all Contributors, as well as any or all Internal Modules.
Module: means a set of sources files including their documentation that
enables supplementary functions or services in addition to those offered
by the Software.
External Module: means any or all Modules, not derived from the
Software, so that this Module and the Software run in separate address
spaces, with one calling the other when they are run.
Internal Module: means any or all Module, connected to the Software so
that they both execute in the same address space.
GNU GPL: means the GNU General Public License version 2 or any
subsequent version, as published by the Free Software Foundation Inc.
Parties: mean both the Licensee and the Licensor.
These expressions may be used both in singular and plural form.
Article 2 - PURPOSE
The purpose of the Agreement is the grant by the Licensor to the
Licensee of a non-exclusive, transferable and worldwide license for the
Software as set forth in Article 5 hereinafter for the whole term of the
protection granted by the rights over said Software.
Article 3 - ACCEPTANCE
3.1 The Licensee shall be deemed as having accepted the terms and
conditions of this Agreement upon the occurrence of the first of the
following events:
* (i) loading the Software by any or all means, notably, by
downloading from a remote server, or by loading from a physical
medium;
* (ii) the first time the Licensee exercises any of the rights
granted hereunder.
3.2 One copy of the Agreement, containing a notice relating to the
characteristics of the Software, to the limited warranty, and to the
fact that its use is restricted to experienced users has been provided
to the Licensee prior to its acceptance as set forth in Article 3.1
hereinabove, and the Licensee hereby acknowledges that it has read and
understood it.
Article 4 - EFFECTIVE DATE AND TERM
4.1 EFFECTIVE DATE
The Agreement shall become effective on the date when it is accepted by
the Licensee as set forth in Article 3.1.
4.2 TERM
The Agreement shall remain in force for the entire legal term of
protection of the economic rights over the Software.
Article 5 - SCOPE OF RIGHTS GRANTED
The Licensor hereby grants to the Licensee, who accepts, the following
rights over the Software for any or all use, and for the term of the
Agreement, on the basis of the terms and conditions set forth hereinafter.
Besides, if the Licensor owns or comes to own one or more patents
protecting all or part of the functions of the Software or of its
components, the Licensor undertakes not to enforce the rights granted by
these patents against successive Licensees using, exploiting or
modifying the Software. If these patents are transferred, the Licensor
undertakes to have the transferees subscribe to the obligations set
forth in this paragraph.
5.1 RIGHT OF USE
The Licensee is authorized to use the Software, without any limitation
as to its fields of application, with it being hereinafter specified
that this comprises:
1. permanent or temporary reproduction of all or part of the Software
by any or all means and in any or all form.
2. loading, displaying, running, or storing the Software on any or
all medium.
3. entitlement to observe, study or test its operation so as to
determine the ideas and principles behind any or all constituent
elements of said Software. This shall apply when the Licensee
carries out any or all loading, displaying, running, transmission
or storage operation as regards the Software, that it is entitled
to carry out hereunder.
5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS
The right to make Contributions includes the right to translate, adapt,
arrange, or make any or all modifications to the Software, and the right
to reproduce the resulting software.
The Licensee is authorized to make any or all Contributions to the
Software provided that it includes an explicit notice that it is the
author of said Contribution and indicates the date of the creation thereof.
5.3 RIGHT OF DISTRIBUTION
In particular, the right of distribution includes the right to publish,
transmit and communicate the Software to the general public on any or
all medium, and by any or all means, and the right to market, either in
consideration of a fee, or free of charge, one or more copies of the
Software by any means.
The Licensee is further authorized to distribute copies of the modified
or unmodified Software to third parties according to the terms and
conditions set forth hereinafter.
5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION
The Licensee is authorized to distribute true copies of the Software in
Source Code or Object Code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's
warranty and liability as set forth in Articles 8 and 9,
and that, in the event that only the Object Code of the Software is
redistributed, the Licensee allows future Licensees unhindered access to
the full Source Code of the Software by indicating how to access it, it
being understood that the additional cost of acquiring the Source Code
shall not exceed the cost of transferring the data.
5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE
When the Licensee makes a Contribution to the Software, the terms and
conditions for the distribution of the resulting Modified Software
become subject to all the provisions of this Agreement.
The Licensee is authorized to distribute the Modified Software, in
source code or object code form, provided that said distribution
complies with all the provisions of the Agreement and is accompanied by:
1. a copy of the Agreement,
2. a notice relating to the limitation of both the Licensor's
warranty and liability as set forth in Articles 8 and 9,
and that, in the event that only the Object Code of the Modified
Software is redistributed, the Licensee allows future Licensees
unhindered access to the full source code of the Modified Software by
indicating how to access it, it being understood that the additional
cost of acquiring the source code shall not exceed the cost of
transferring the data.
5.3.3 DISTRIBUTION OF EXTERNAL MODULES
When the Licensee has developed an External Module, the terms and
conditions of this Agreement do not apply to said External Module, that
may be distributed under a separate license agreement.
5.3.4 COMPATIBILITY WITH THE GNU GPL
The Licensee can include a code that is subject to the provisions of one
of the versions of the GNU GPL in the Modified or unmodified Software,
and distribute that entire code under the terms of the same version of
the GNU GPL.
The Licensee can include the Modified or unmodified Software in a code
that is subject to the provisions of one of the versions of the GNU GPL,
and distribute that entire code under the terms of the same version of
the GNU GPL.
Article 6 - INTELLECTUAL PROPERTY
6.1 OVER THE INITIAL SOFTWARE
The Holder owns the economic rights over the Initial Software. Any or
all use of the Initial Software is subject to compliance with the terms
and conditions under which the Holder has elected to distribute its work
and no one shall be entitled to modify the terms and conditions for the
distribution of said Initial Software.
The Holder undertakes that the Initial Software will remain ruled at
least by the current license, for the duration set forth in Article 4.2.
6.2 OVER THE CONTRIBUTIONS
A Licensee who develops a Contribution is the owner of the intellectual
property rights over this Contribution as defined by applicable law.
6.3 OVER THE EXTERNAL MODULES
A Licensee who develops an External Module is the owner of the
intellectual property rights over this External Module as defined by
applicable law and is free to choose the type of agreement that shall
govern its distribution.
6.4 JOINT PROVISIONS
The Licensee expressly undertakes:
1. not to remove, or modify, in any manner, the intellectual property
notices attached to the Software;
2. to reproduce said notices, in an identical manner, in the copies
of the Software modified or not.
The Licensee undertakes not to directly or indirectly infringe the
intellectual property rights of the Holder and/or Contributors on the
Software and to take, where applicable, vis-à-vis its staff, any and all
measures required to ensure respect of said intellectual property rights
of the Holder and/or Contributors.
Article 7 - RELATED SERVICES
7.1 Under no circumstances shall the Agreement oblige the Licensor to
provide technical assistance or maintenance services for the Software.
However, the Licensor is entitled to offer this type of services. The
terms and conditions of such technical assistance, and/or such
maintenance, shall be set forth in a separate instrument. Only the
Licensor offering said maintenance and/or technical assistance services
shall incur liability therefor.
7.2 Similarly, any Licensor is entitled to offer to its licensees, under
its sole responsibility, a warranty, that shall only be binding upon
itself, for the redistribution of the Software and/or the Modified
Software, under terms and conditions that it is free to decide. Said
warranty, and the financial terms and conditions of its application,
shall be subject of a separate instrument executed between the Licensor
and the Licensee.
Article 8 - LIABILITY
8.1 Subject to the provisions of Article 8.2, the Licensee shall be
entitled to claim compensation for any direct loss it may have suffered
from the Software as a result of a fault on the part of the relevant
Licensor, subject to providing evidence thereof.
8.2 The Licensor's liability is limited to the commitments made under
this Agreement and shall not be incurred as a result of in particular:
(i) loss due the Licensee's total or partial failure to fulfill its
obligations, (ii) direct or consequential loss that is suffered by the
Licensee due to the use or performance of the Software, and (iii) more
generally, any consequential loss. In particular the Parties expressly
agree that any or all pecuniary or business loss (i.e. loss of data,
loss of profits, operating loss, loss of customers or orders,
opportunity cost, any disturbance to business activities) or any or all
legal proceedings instituted against the Licensee by a third party,
shall constitute consequential loss and shall not provide entitlement to
any or all compensation from the Licensor.
Article 9 - WARRANTY
9.1 The Licensee acknowledges that the scientific and technical
state-of-the-art when the Software was distributed did not enable all
possible uses to be tested and verified, nor for the presence of
possible defects to be detected. In this respect, the Licensee's
attention has been drawn to the risks associated with loading, using,
modifying and/or developing and reproducing the Software which are
reserved for experienced users.
The Licensee shall be responsible for verifying, by any or all means,
the suitability of the product for its requirements, its good working order,
and for ensuring that it shall not cause damage to either persons or
properties.
9.2 The Licensor hereby represents, in good faith, that it is entitled
to grant all the rights over the Software (including in particular the
rights set forth in Article 5).
9.3 The Licensee acknowledges that the Software is supplied "as is" by
the Licensor without any other express or tacit warranty, other than
that provided for in Article 9.2 and, in particular, without any warranty
as to its commercial value, its secured, safe, innovative or relevant
nature.
Specifically, the Licensor does not warrant that the Software is free
from any error, that it will operate without interruption, that it will
be compatible with the Licensee's own equipment and software
configuration, nor that it will meet the Licensee's requirements.
9.4 The Licensor does not either expressly or tacitly warrant that the
Software does not infringe any third party intellectual property right
relating to a patent, software or any other property right. Therefore,
the Licensor disclaims any and all liability towards the Licensee
arising out of any or all proceedings for infringement that may be
instituted in respect of the use, modification and redistribution of the
Software. Nevertheless, should such proceedings be instituted against
the Licensee, the Licensor shall provide it with technical and legal
assistance for its defense. Such technical and legal assistance shall be
decided on a case-by-case basis between the relevant Licensor and the
Licensee pursuant to a memorandum of understanding. The Licensor
disclaims any and all liability as regards the Licensee's use of the
name of the Software. No warranty is given as regards the existence of
prior rights over the name of the Software or as regards the existence
of a trademark.
Article 10 - TERMINATION
10.1 In the event of a breach by the Licensee of its obligations
hereunder, the Licensor may automatically terminate this Agreement
thirty (30) days after notice has been sent to the Licensee and has
remained ineffective.
10.2 A Licensee whose Agreement is terminated shall no longer be
authorized to use, modify or distribute the Software. However, any
licenses that it may have granted prior to termination of the Agreement
shall remain valid subject to their having been granted in compliance
with the terms and conditions hereof.
Article 11 - MISCELLANEOUS
11.1 EXCUSABLE EVENTS
Neither Party shall be liable for any or all delay, or failure to
perform the Agreement, that may be attributable to an event of force
majeure, an act of God or an outside cause, such as defective
functioning or interruptions of the electricity or telecommunications
networks, network paralysis following a virus attack, intervention by
government authorities, natural disasters, water damage, earthquakes,
fire, explosions, strikes and labor unrest, war, etc.
11.2 Any failure by either Party, on one or more occasions, to invoke
one or more of the provisions hereof, shall under no circumstances be
interpreted as being a waiver by the interested Party of its right to
invoke said provision(s) subsequently.
11.3 The Agreement cancels and replaces any or all previous agreements,
whether written or oral, between the Parties and having the same
purpose, and constitutes the entirety of the agreement between said
Parties concerning said purpose. No supplement or modification to the
terms and conditions hereof shall be effective as between the Parties
unless it is made in writing and signed by their duly authorized
representatives.
11.4 In the event that one or more of the provisions hereof were to
conflict with a current or future applicable act or legislative text,
said act or legislative text shall prevail, and the Parties shall make
the necessary amendments so as to comply with said act or legislative
text. All other provisions shall remain effective. Similarly, invalidity
of a provision of the Agreement, for any reason whatsoever, shall not
cause the Agreement as a whole to be invalid.
11.5 LANGUAGE
The Agreement is drafted in both French and English and both versions
are deemed authentic.
Article 12 - NEW VERSIONS OF THE AGREEMENT
12.1 Any person is authorized to duplicate and distribute copies of this
Agreement.
12.2 So as to ensure coherence, the wording of this Agreement is
protected and may only be modified by the authors of the License, who
reserve the right to periodically publish updates or new versions of the
Agreement, each with a separate number. These subsequent versions may
address new issues encountered by Free Software.
12.3 Any Software distributed under a given version of the Agreement may
only be subsequently distributed under the same version of the Agreement
or a subsequent version, subject to the provisions of Article 5.3.4.
Article 13 - GOVERNING LAW AND JURISDICTION
13.1 The Agreement is governed by French law. The Parties agree to
endeavor to seek an amicable solution to any disagreements or disputes
that may arise during the performance of the Agreement.
13.2 Failing an amicable solution within two (2) months as from their
occurrence, and unless emergency proceedings are necessary, the
disagreements or disputes shall be referred to the Paris Courts having
jurisdiction, by the more diligent Party.
Version 2.0 dated 2006-07-12.

24
README.md Normal file
View file

@ -0,0 +1,24 @@
<a href="http://cimg.eu">![Logo](http://cimg.eu/img/CImgLogo2.jpg)</a>
##### http://cimg.eu
------------------
The **CImg Library** is a **small** and **open-source** **C++ toolkit** for **image processing**, designed with these properties in mind:
![Usefulness](http://cimg.eu/img/item_usefulness.jpg) **CImg** defines *classes* and *methods* to manage images in your own C++ code. You can use **CImg** to load/save various file formats, access pixel values, display/transform/filter images, draw primitives (text, faces, curves, 3d objects, ...), compute statistics, manage user interactions on images, and so on...
![Genericity](http://cimg.eu/img/item_genericity.jpg) **CImg** defines a single image class able to represent datasets having up to *4-dimensions* (from 1d scalar signals to 3d hyperspectral volumetric images), with *template pixel types* (`bool,char,int,float,...`). It also handles image *collections* and *sequences*.
![Portability](http://cimg.eu/img/item_portability.jpg) **CImg** is *self-contained*, *thread-safe* and *highly portable*. It fully works on *different operating systems* (`Unix,Windows,MacOS X,*BSD,...`) and is compatible with *various C++ compilers* (`Visual C++,g++,clang++,icc,...`).
![Simplicity](http://cimg.eu/img/item_simplicity.jpg) **CImg** is *lightweight*. It is made of a single header file [`CImg.h`](https://github.com/dtschump/CImg/raw/master/CImg.h) that must be included in your C++ source. It defines only *four* different classes, encapsulated in the namespace `cimg_library`. It can be compiled using a minimal set of standard C++ and system libraries only. *No need for exotic or complex dependencies*.
![Extensibility](http://cimg.eu/img/item_extensibility.jpg) Although not mandatory, **CImg** can use functionalities of external tools/libraries such as [Board](http://libboard.sourceforge.net/), [FFMPEG](http://ffmpeg.mplayerhq.hu/), [FFTW3](http://www.fftw.org/), [GraphicsMagick](http://www.graphicsmagick.org/), [ImageMagick](http://www.imagemagick.org/), [Lapack](http://www.netlib.org/lapack/), [libcurl](http://curl.haxx.se/libcurl/), [libjpeg](http://www.ijg.org/), [libpng](http://www.libpng.org/pub/png/libpng.html), [libtiff](http://www.libtiff.org/), [Magick++](http://www.imagemagick.org/Magick++/), [OpenEXR](http://www.openexr.com/), [OpenCV](http://http://opencv.willowgarage.com/wiki/), [OpenMP](http://www.openmp.org/) or [XMedCon](http://xmedcon.sourceforge.net/). Moreover, a simple *plug-in* mechanism allows any user to directly enhance the library capabilities according to their needs.
![Freedom](http://cimg.eu/img/item_freedom.jpg) **CImg** is a *free, open-source library* distributed under the [*CeCILL-C*](http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.txt) (close to the GNU LGPL) or [CeCILL](http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt) (compatible with the GNU GPL) licenses. It can be used in commercial applications.
------------------
> **CImg** stands for **Cool Image** : It is _easy to use_, _efficient_ and is intended to be a very pleasant toolbox to design image processing algorithms in C++. Due to its generic conception, it can cover a wide range of image processing applications.
------------------

180
README.txt Normal file
View file

@ -0,0 +1,180 @@
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
____ _ _ ____
(_ _)( )_( )( ___)
)( ) _ ( )__)
(__) (_) (_)(____)
___ ____ __ __ ___ __ ____ ____ ____ __ ____ _ _
/ __)(_ _)( \/ )/ __) ( ) (_ _)( _ \( _ \ /__\ ( _ \( \/ )
( (__ _)(_ ) (( (_-. )(__ _)(_ ) _ < ) / /(__)\ ) / \ /
\___)(____)(_/\/\_)\___/ (____)(____)(____/(_)\_)(__)(__)(_)\_) (__)
C++ Template Image Processing Toolkit
( http://cimg.eu )
_cimg_version
--------------------------------------------------------------------------------
# Summary
#---------
The CImg Library is a small and open-source C++ toolkit for image processing.
It consists in a single header file 'CImg.h' providing a minimal set of C++
classes and methods that can be used in your own sources, to load/save,
process and display images. Very portable (Unix/X11,Windows, MacOS X, FreeBSD, .. ),
efficient, easy to use, it's a pleasant library for developing image processing
algorithms in C++.
# Authors and contributors :
#----------------------------
- David Tschumperlé (project leader) ( http://tschumperle.users.greyc.fr/ )
- Maksim Aizenshtein
- Alberto Albiol
- Antonio Albiol
- Simon Barthelme
- Neil Brown
- Haz-Edine Assemlal
- Vincent Barra
- Wolf Blecher
- Romain Blei
- Yohan Bentolila
- Jerome Boulanger
- Pierre Buyssens
- Sebastien Coudert
- Frederic Devernay
- Olivier D'Hondt
- Francois-Xavier Dupe
- Gerd von Egidy
- Eric Fausett
- Jean-Marie Favreau
- Sebastien Fourey
- Alexandre Fournier
- Hon-Kwok Fung
- Vincent Garcia
- David Grimbichler
- Jinwei Gu
- Jean-Daniel Guyot
- Cedric Hammiche
- Matt Hanson
- Sebastien Hanel
- Michael Holroyd
- Christoph Hormann
- Werner Jainek
- Daniel Kondermann
- Pierre Kornprobst
- Jan W. Krieger
- Orges Leka
- Francois Lauze
- Xie Long
- Thomas Martin
- Cesar Martinez
- Jean Martinot
- Arnold Meijster (Center for High Performance Computing and Visualization, University of Groningen/The Netherlands)
- Nikita Melnichenko
- Julien Morat
- Baptiste Mougel
- Jovana Milutinovich
- Guillaume Nee
- Adam Newgas
- Francisco Oliveira
- Andrea Onofri
- Renaud Peteri
- Martin Petricek
- Paolo Prete
- Adrien Reboisson
- Klaus Schneider
- Jakob Schluttig
- Jamie Smith
- Veronique Souchaud
- Konstantin Spirin
- David G. Starkweather
- Rainer Steffens
- Grzegorz Szwoch
- Thierry Thomas
- Yu-En-Yun
- Vo Duc Khanh
- Phillip Wood
- Bug Zhao
- Haibo Zheng
# Institution
#-------------
GREYC Image / CNRS UMR 6072 / FRANCE
The CImg Library project started in 2000, at the INRIA-Sophia
Antipolis/France ( http://www-sop.inria.fr/ ), in the ROBOTVIS / ODYSSEE Team.
Since October 2004, it is maintained and developed in the Image team of
the GREYC Lab (CNRS, UMR 6072), in Caen/France.
Team web page : http://www.greyc.fr/image
# Licenses
#----------
The source code of the CImg Library is distributed under
two distinct licenses :
- The main library file 'CImg.h' is *dual-licensed* :
It can be either distributed under the CeCILL-C or CeCILL license.
(see files 'Licence_CeCILL-C_V1-en.txt' and 'Licence_CeCILL_V2-en.txt').
Both are Free-Software licenses :
* CeCILL-C is adapted to the distribution of
library components, and is close in its terms to the well known GNU LGPL license
(the 'CImg.h' file can thus be used in closed-source products under certain
conditions, please read carefully the license file).
* CeCILL is close to (and even compatible with) the GNU GPL license.
- Most of the other files are distributed under the CeCiLL license
(file 'Licence_CeCILL_V2-en.txt'). See each file header to see what license applies.
These two CeCiLL licenses ( http://www.cecill.info/index.en.html ) have been
created under the supervision of the three biggest research institutions on
computer sciences in France :
- CNRS ( http://www.cnrs.fr/ )
- CEA ( http://www.cea.fr/ )
- INRIA ( http://www.inria.fr/ )
You have to RESPECT these licenses. More particularly, please carefully read
the license terms before using the CImg library in commercial products.
# Package structure :
#--------------------
The main package directory CImg/ is organized as follows :
- README.txt : This file.
- Licence_CeCILL-C_V1-en.txt : A copy of the CeCiLL-C license file.
- Licence_CeCILL_V2-en.txt : A copy of the CeCiLL license.
- CImg.h : The single header file that constitutes the library itself.
- examples/ : A directory containing a lot of example programs performing
various things, using the CImg library.
- html/ : A directory containing a copy of the CImg web page in html
format. The reference documentation is generated
automatically with the tool 'doxygen' (http://www.doxygen.org).
- resources/ : A directory containing some resources files for compiling
CImg examples or packages with various C++ compilers and OS.
- plugins/ : A directory containing CImg plug-ins files that can be used to
add specific extra functionalities to the CImg library.
# Getting started
#-----------------
If you are new to CImg, you should first try to compile the different examples
provided in the 'examples/' directory, to see what CImg is capable of
(as CImg is a template-based library, no prior compilation of the library is mandatory).
Look at the 'resources/' directory to ease this compilation on different platforms.
Then, you can look at the documentation 'html/reference/' to learn more about CImg
functions and classes. Finally, you can participate to the 'Forum' section
of the CImg web page and ask for help if needed.
# End of file
#------------

1712
examples/CImg_demo.cpp Normal file

File diff suppressed because it is too large Load diff

310
examples/CMakeLists.txt Normal file
View file

@ -0,0 +1,310 @@
#
# File : CMakeLists.txt
# ( Configuration file for 'cmake' utility )
#
# Description : CMakeLists.txt configuration file for compiling CImg-based code.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Antonio Albiol
# ( http://personales.upv.es/~aalbiol/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
cmake_minimum_required(VERSION 2.6)
PROJECT(Examples-CIMG)
# Prevent compilation in-source
if( ${CMAKE_BINARY_DIR} STREQUAL ${PROJECT_SOURCE_DIR} )
Message( " " )
Message( FATAL_ERROR "Source and build directories are the same.
Create an empty build directory,
change into it and re-invoke cmake")
endif()
# To use PKG_CHECK_MODULES to find some optional packages
find_package(PkgConfig)
# Tell CMake where to leave executables
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
#Path of CImg.h file relative to this file path
set(CIMG_H_PATH ${PROJECT_SOURCE_DIR}/..)
include_directories( ${PROJECT_SOURCE_DIR} )
include_directories( ${CIMG_H_PATH} )
# ### CIMG related stuff
# Flags to enable fast image display, using the XSHM library.
SET(CIMG_XSHM_CCFLAGS -Dcimg_use_xshm)
# Flags to enable screen mode switching, using the XRandr library.
SET(CIMG_XRANDR_CCFLAGS -Dcimg_use_xrandr)
# Flags to enable native support for JPEG image files, using the JPEG library.
# ( http://www.ijg.org/ )
SET(CIMG_JPEG_CCFLAGS -Dcimg_use_jpeg)
# Flags to enable native support for TIFF image files, using the TIFF library.
# ( http://www.libtiff.org/ )
SET(CIMG_TIFF_CCFLAGS -Dcimg_use_tiff)
# Flags to enable native support for PNG image files, using the PNG library.
# ( http://www.libpng.org/ )
SET(CIMG_PNG_CCFLAGS -Dcimg_use_png)
#Flags to enable OPENCV support (Camera)
# ( http://www.opencv.org/ )
SET(CIMG_OPENCV_CCFLAGS-Dcimg_use_opencv)
# Flags to enable native support for EXR image files, using the OpenEXR library.
# ( http://www.openexr.com/ )
SET(CIMG_OPENEXR_CCFLAGS -Dcimg_use_openexr)
# Flags to enable native support for various video files, using the FFMPEG library.
# ( http://www.ffmpeg.org/ )
SET(CIMG_FFMPEG_CCFLAGS -Dcimg_use_ffmpeg)
# Flags to enable native support of most classical image file formats, using the Magick++ library.
# ( http://www.imagemagick.org/Magick++/ )
SET(CIMG_MAGICK_CCFLAGS -Dcimg_use_magick)
# Flags to enable faster Discrete Fourier Transform computation, using the FFTW3 library
# ( http://www.fftw.org/ )
SET(CIMG_FFTW3_CCFLAGS -Dcimg_use_fftw3)
# ### Search Additional Libraries ##########
FIND_PACKAGE(OpenCV)
FIND_PACKAGE(JPEG)
FIND_PACKAGE(TIFF)
FIND_PACKAGE(PNG)
FIND_PACKAGE(ZLIB)
FIND_PACKAGE(LAPACK)
FIND_PACKAGE(BLAS)
PKG_CHECK_MODULES(FFTW3 fftw3)
PKG_CHECK_MODULES(OPENEXR OpenEXR)
PKG_CHECK_MODULES(MAGICK Magick++)
# PKG_CHECK_MODULES(LIBAVCODEC libavcodec)
# PKG_CHECK_MODULES(LIBAVFORMAT libavformat)
# PKG_CHECK_MODULES(LIBSWSCALE libswscale)
# PKG_CHECK_MODULES(LIBAVUTIL libavutil)
if(NOT WIN32)
FIND_PACKAGE(X11)
FIND_PACKAGE(Threads REQUIRED)
endif()
# #### End of additional libraries search ##########
### Configure Paths according to detected packages
if(TIFF_FOUND)
get_filename_component(TIFF_LIB_DIRS ${TIFF_LIBRARIES} PATH)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_TIFF_CCFLAGS}")
link_directories(${TIFF_LIB_DIRS})
include_directories(${TIFF_INCLUDE_DIR})
SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${TIFF_LIBRARIES})
endif()
if(JPEG_FOUND)
get_filename_component(JPEG_LIB_DIRS ${JPEG_LIBRARIES} PATH)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_JPEG_CCFLAGS}")
link_directories(${JPEG_LIB_DIRS})
include_directories(${JPEG_INCLUDE_DIR})
SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${JPEG_LIBRARIES})
endif()
if (ZLIB_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_ZLIB_CCFLAGS}")
link_directories(${ZLIB_LIB_DIRS})
include_directories(${ZLIB_INCLUDE_DIR})
SET(SYSTEM_LIBS ${SYSTEM_LIBS} ${ZLIB_LIBRARIES})
# PNG requires ZLIB
if(PNG_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_PNG_CCFLAGS}")
link_directories(${PNG_LIB_DIRS})
include_directories(${PNG_INCLUDE_DIR} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${PNG_LIBRARIES} )
endif()
endif()
if(FFTW3_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_FFTW3_CCFLAGS}")
link_directories( ${FFTW3_LIBRARY_DIRS} )
include_directories( ${FFTW3_INCLUDE_DIRS} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${FFTW3_LIBRARIES} )
endif()
if(OPENEXR_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_OPENEXR_CCFLAGS}")
link_directories( ${OPENEXR_LIBRARY_DIRS} )
include_directories( ${OPENEXR_INCLUDE_DIRS} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${OPENEXR_LIBRARIES} )
endif()
if(MAGICK_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_MAGICK_CCFLAGS}")
link_directories( ${MAGICK_LIBRARY_DIRS} )
include_directories( ${MAGICK_INCLUDE_DIRS} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${MAGICK_LIBRARIES} )
endif()
if( LIBAVCODEC_FOUND AND LIBAVFORMAT_FOUND AND LIBSWSCALE_FOUND AND LIBAVUTIL_FOUND )
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_FFMPEG_CCFLAGS}")
link_directories( ${LIBAVFORMAT_LIBRARY_DIRS} )
link_directories( ${LIBAVCODEC_LIBRARY_DIRS} )
link_directories( ${LIBSWSCALE_LIBRARY_DIRS} )
link_directories( ${LIBAVUTIL_LIBRARY_DIRS} )
include_directories( ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS}/libavformat)
include_directories( ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVCODEC_INCLUDE_DIRS}/libavcodec )
include_directories( ${LIBSWSCALE_INCLUDE_DIRS} ${LIBSWSCALE_INCLUDE_DIRS}/libswscale)
include_directories( ${LIBAVUTIL_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS}/libavutil )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBAVFORMAT_LIBRARIES} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBAVCODEC_LIBRARIES} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBSWSCALE_LIBRARIES} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${LIBAVUTIL_LIBRARIES} )
endif()
if(NOT APPLE)
if(NOT WIN32)
if(X11_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_XSHM_CCFLAGS} ${CIMG_XRANDR_CCFLAGS}")
SET(SYSTEM_LIBS ${SYSTEM_LIBS} Xext Xrandr)
endif()
endif(NOT WIN32)
endif(NOT APPLE)
if(X11_FOUND)
link_directories(${X11_LIB_DIRS})
include_directories(${X11_INCLUDE_DIR})
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${X11_LIBRARIES} )
endif()
if (NOT WIN32)
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${CMAKE_THREAD_LIBS_INIT} )
endif()
if( WIN32)
SET( SYSTEM_LIBS ${SYSTEM_LIBS} gdi32 )
endif()
if (OpenCV_FOUND)
message("OpenCV Found")
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_OPENCV_CCFLAGS}")
include_directories(${OpenCV_INCLUDE_DIRS})
link_directories(${OpenCV_LIB_DIRS})
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${OpenCV_LIBS} )
endif()
if(LAPACK_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_LAPACK_CCFLAGS}")
link_directories( ${LAPACK_LIBRARY_DIRS} )
include_directories( ${LAPACK_INCLUDE_DIRS} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${LAPACK_LIBRARIES} )
endif()
if(BLAS_FOUND)
SET(CIMG_CFLAGS "${CIMG_CFLAGS} ${CIMG_BLAS_CCFLAGS}")
link_directories( ${BLAS_LIBRARY_DIRS} )
include_directories( ${BLAS_INCLUDE_DIRS} )
SET( SYSTEM_LIBS ${SYSTEM_LIBS} ${BLAS_LIBRARIES} )
endif()
# Add CIMG Flags to Compilation Flags
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CIMG_CFLAGS}")
SET(CIMG_FILES CImg_demo
captcha
curve_editor2d
dtmri_view3d
edge_explorer2d
fade_images
gaussian_fit1d
generate_loop_macros
hough_transform2d
image_registration2d
image2ascii
image_surface3d
jawbreaker
mcf_levelsets2d
mcf_levelsets3d
odykill
pde_heatflow2d
pde_TschumperleDeriche2d
plotter1d
radon_transform2d
scene3d
spherical_function3d
tetris
tron
tutorial
wavelet_atrous
use_draw_gradient
use_nlmeans
use_skeleton
use_RGBclass
)
foreach(program ${CIMG_FILES})
add_executable(${program} ${program}.cpp)
target_link_libraries(${program} ${SYSTEM_LIBS} )
endforeach(program)

609
examples/Makefile Normal file
View file

@ -0,0 +1,609 @@
#
# File : Makefile
# ( Makefile for GNU 'make' utility )
#
# Description : Makefile for compiling CImg-based code on Unix.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
#-------------------------------------------------------
# Define the list of files to be compiled
# (name of the source files without the .cpp extension)
#-------------------------------------------------------
# Files which do not necessarily require external libraries to run.
FILES = CImg_demo \
captcha \
curve_editor2d \
dtmri_view3d \
edge_explorer2d \
fade_images \
gaussian_fit1d \
generate_loop_macros \
hough_transform2d \
image_registration2d \
image2ascii \
image_surface3d \
jawbreaker \
mcf_levelsets2d \
mcf_levelsets3d \
odykill \
pde_heatflow2d \
pde_TschumperleDeriche2d \
plotter1d \
radon_transform2d \
scene3d \
spherical_function3d \
tetris \
tron \
tutorial \
wavelet_atrous \
use_chlpca \
use_draw_gradient \
use_nlmeans \
use_skeleton \
use_RGBclass \
# Files which requires external libraries to run.
EXTRA_FILES = use_tiff_stream use_jpeg_buffer
#---------------------------------
# Set correct variables and paths
#---------------------------------
VERSION = $(shell grep 'cimg_version\ ' ../CImg.h | tail -c4 | head -c3)
VERSION1 = $(shell grep 'cimg_version\ ' ../CImg.h | tail -c4 | head -c1)
VERSION2 = $(shell grep 'cimg_version\ ' ../CImg.h | tail -c3 | head -c1)
VERSION3 = $(shell grep 'cimg_version\ ' ../CImg.h | tail -c2 | head -c1)
SVERSION = $(VERSION1).$(VERSION2).$(VERSION3)
X11PATH = /usr/X11R6
EXE_PRE =
EXE_EXT =
ifeq ($(MSYSTEM),MINGW32)
EXE_EXT = .exe
endif
ifeq ($(MSYSTEM),MINGW64)
EXE_EXT = .exe
endif
ifeq ($(shell echo $(notdir $(CXX)) | head -c3),g++)
IS_GCC = 1
endif
ifeq ($(shell echo $(notdir $(CXX)) | head -c7),clang++)
IS_CLANG = 1
endif
ifeq ($(shell echo $(notdir $(CXX)) | head -c4),icpc)
IS_ICPC = 1
endif
CXXVER = $(CXX)
CFLAGS = -I.. -Wall -Wextra -Wfatal-errors -Werror=unknown-pragmas -Werror=unused-label
LIBS = -lm
ifdef IS_GCC
CXXVER = $(shell $(CXX) -v 2>&1 | tail -n 1)
endif
ifdef IS_CLANG
CXXVER = $(shell $(CXX) -v 2>&1 | head -n 1)
endif
ifdef IS_ICPC
CXXVER = $(shell $(CXX) -v 2>&1)
CFLAGS = -I..
LIBS =
endif
ifdef IS_GCC
GCC_VER_GTEQ5 = $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 5)
ifeq ($(GCC_VER_GTEQ5),1)
CFLAGS += -Wshadow
endif
endif
#--------------------------------------------------
# Set compilation flags allowing to customize CImg
#--------------------------------------------------
# Flags to enable strict code standards
ifeq ($(notdir $(CXX)),icpc)
ANSI_CFLAGS = -std=c++11
else
ANSI_CFLAGS = -std=c++11 -pedantic
endif
# Flags to enable code debugging.
DEBUG_CFLAGS = -Dcimg_verbosity=3 -Dcimg_strict_warnings -g -fsanitize=address
# Flags to enable color output messages.
# (requires a VT100 compatible terminal)
VT100_CFLAGS = -Dcimg_use_vt100
# Flags to enable code optimization by the compiler.
OPT_CFLAGS = -Ofast
ifdef IS_GCC
OPT_CFLAGS = -Ofast -mtune=generic
endif
ifdef IS_ICPC
OPT_CFLAGS = -fast
endif
# Flags to enable OpenMP support.
OPENMP_DEFINE = -Dcimg_use_openmp -fopenmp
OPENMP_INCDIR =
OPENMP_CFLAGS = $(OPENMP_DEFINE) $(OPENMP_INCDIR)
ifdef IS_ICPC
OPENMP_CFLAGS = #-Dcimg_use_openmp -openmp -i-static # -> Seems to bug the compiler!
endif
ifdef IS_CLANG
OPENMP_CFLAGS =
endif
# Flags to enable OpenCV support.
OPENCV_DEFINE = -Dcimg_use_opencv
OPENCV_INCDIR = $(shell pkg-config opencv --cflags || echo -I/usr/include/opencv) -I/usr/include/opencv -I/usr/include/opencv4
OPENCV_CFLAGS = $(OPENCV_DEFINE) $(OPENCV_INCDIR)
OPENCV_LIBS = $(shell pkg-config opencv --libs || echo -lopencv_core -lopencv_highgui)
# Flags used to disable display capablities of CImg
NODISPLAY_CFLAGS = -Dcimg_display=0
# Flags to enable the use of the X11 library.
# (X11 is used by CImg to handle display windows)
X11_DEFINE = -Dcimg_display=1
X11_INCDIR = $(shell pkg-config --cflags x11 || echo -I/usr/X11R6/include)
X11_CFLAGS = $(X11_DEFINE) $(X11_INCDIR)
X11_LIBS = $(shell pkg-config --libs x11 || echo -L/usr/X11R6/lib -lX11) -lpthread
# Flags to enable fast image display, using the XSHM library (when using X11).
# !!! Seems to randomly crash when used on MacOS and 64bits systems, so use it only when necessary !!!
XSHM_CFLAGS = # -Dcimg_use_xshm $(shell pkg-config --cflags xcb-shm)
XSHM_LIBS = # $(shell pkg-config --libs xcb-shm || echo -L$(USR)/X11R6/lib -lXext)
# Flags to enable GDI32 display (Windows native).
GDI32_DEFINE = -mwindows
GDI32_INCDIR =
GDI32_CFLAGS = $(GDI32_DEFINE) $(GDI32_INCDIR)
GDI32_LIBS = -lgdi32
# Flags to enable screen mode switching, using the XRandr library (when using X11).
# ( http://www.x.org/wiki/Projects/XRandR )
# !!! Not supported by the X11 server on MacOS, so do not use it on MacOS !!!
XRANDR_DEFINE = -Dcimg_use_xrandr
XRANDR_INCDIR =
XRANDR_CFLAGS = $(XRANDR_DEFINE) $(XRANDR_INCDIR)
XRANDR_LIBS = -lXrandr
# Flags to enable native support for PNG image files, using the PNG library.
# ( http://www.libpng.org/ )
PNG_DEFINE = -Dcimg_use_png
PNG_INCDIR =
PNG_CFLAGS = $(PNG_DEFINE) $(PNG_INCDIR)
PNG_LIBS = -lpng -lz
# Flags to enable native support for JPEG image files, using the JPEG library.
# ( http://www.ijg.org/ )
JPEG_DEFINE = -Dcimg_use_jpeg
JPEG_INCDIR =
JPEG_CFLAGS = $(JPEG_DEFINE) $(JPEG_INCDIR)
JPEG_LIBS = -ljpeg
# Flags to enable native support for TIFF image files, using the TIFF library.
# ( http://www.libtiff.org/ )
TIFF_DEFINE = -Dcimg_use_tiff
TIFF_INCDIR =
TIFF_CFLAGS = $(TIFF_DEFINE) $(TIFF_INCDIR)
TIFF_LIBS = -ltiff
# Flags to enable native support for loading HEIF image files, using the libheif library.
# ( https://github.com/strukturag/libheif )
HEIF_DEFINE = -Dcimg_use_heif
HEIF_INCDIR =
HEIF_CFLAGS = $(HEIF_DEFINE) $(HEIF_INCDIR)
HEIF_LIBS = -lheif
# Flags to enable native support for MINC2 image files, using the MINC2 library.
# ( http://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_Users_Guide )
MINC2_DEFINE = -Dcimg_use_minc2
MINC2_INCDIR = -I${HOME}/local/include
MINC2_CFLAGS = $(MINC2_DEFINE) $(MINC2_INCDIR)
MINC2_LIBS = -lminc_io -lvolume_io2 -lminc2 -lnetcdf -lhdf5 -lz -L${HOME}/local/lib
# Flags to enable native support for EXR image files, using the OpenEXR library.
# ( http://www.openexr.com/ )
OPENEXR_DEFINE = -Dcimg_use_openexr
OPENEXR_INCDIR = -I/usr/include/OpenEXR
OPENEXR_CFLAGS = $(OPENEXR_DEFINE) $(OPENEXR_INCDIR)
OPENEXR_LIBS = -lIlmImf -lHalf
# Flags to enable native support for various video files, using the FFMPEG library.
# ( http://www.ffmpeg.org/ )
FFMPEG_DEFINE = -Dcimg_use_ffmpeg -D__STDC_CONSTANT_MACROS
FFMPEG_INCDIR = -I/usr/include/libavcodec -I/usr/include/libavformat -I/usr/include/libswscale -I/usr/include/ffmpeg
FFMPEG_CFLAGS = $(FFMPEG_DEFINE) $(FFMPEG_INCDIR)
FFMPEG_LIBS = -lavcodec -lavformat -lswscale
# Flags to enable native support for compressed .cimgz files, using the Zlib library.
# ( http://www.zlib.net/ )
ZLIB_DEFINE = -Dcimg_use_zlib
ZLIB_INCDIR = $(shell pkg-config --cflags zlib || echo -I$(USR)/$(INCLUDE))
ZLIB_CFLAGS = $(ZLIB_DEFINE) $(ZLIB_INCDIR)
ZLIB_LIBS = $(shell pkg-config --libs zlib || echo -lz)
# Flags to enable native support for downloading files from the network.
# ( http://curl.haxx.se/libcurl/ )
CURL_DEFINE = -Dcimg_use_curl
CURL_INCDIR =
CURL_CFLAGS = $(CURL_DEFINE)
CURL_LIBS = -lcurl
# Flags to enable native support of most classical image file formats, using the Magick++ library.
# ( http://www.imagemagick.org/Magick++/ )
MAGICK_DEFINE = -Dcimg_use_magick
MAGICK_INCDIR = $(shell pkg-config --cflags GraphicsMagick++ || echo -I$(USR)/$(INCLUDE)/GraphicsMagick)
MAGICK_CFLAGS = $(MAGICK_DEFINE) $(MAGICK_INCDIR)
MAGICK_LIBS = $(shell pkg-config --libs GraphicsMagick++ || echo -lGraphicsMagick++)
# Flags to enable faster Discrete Fourier Transform computation, using the FFTW3 library
# ( http://www.fftw.org/ )
FFTW3_DEFINE = -Dcimg_use_fftw3
FFTW3_INCDIR =
FFTW3_CFLAGS = $(FFTW3_DEFINE) $(FFTW3_INCDIR)
ifeq ($(OSTYPE),msys)
FFTW3_LIBS = -lfftw3-3
else
FFTW3_LIBS = -lfftw3 -lfftw3_threads
endif
# Flags to enable the use of LAPACK routines for matrix computation
# ( http://www.netlib.org/lapack/ )
LAPACK_DEFINE = -Dcimg_use_lapack
LAPACK_INCDIR =
LAPACK_CFLAGS = $(LAPACK_DEFINE) $(LAPACK_INCDIR)
LAPACK_LIBS = -lblas -llapack
# Flags to enable the use of the Board library
# ( https://github.com/c-koi/libboard )
BOARD_DEFINE = -Dcimg_use_board
BOARD_INCDIR = -I/usr/include/board
BOARD_CFLAGS = $(BOARD_DEFINE) $(BOARD_INCDIR)
BOARD_LIBS = -lboard
# Flags to compile GIMP plug-ins.
ifeq ($(MSYSTEM),MINGW32)
GIMP_CFLAGS = -mwindows
endif
#-------------------------
# Define Makefile entries
#-------------------------
.cpp:
@echo
@echo "** Compiling '$* ($(SVERSION))' with '$(CXXVER)'"
@echo
$(CXX) -o $(EXE_PRE)$*$(EXE_EXT) $< $(CFLAGS) $(CONF_CFLAGS) $(LIBS) $(CONF_LIBS)
ifeq ($(STRIP_EXE),true)
strip $(EXE_PRE)$*$(EXE_EXT)
endif
menu:
@echo
@echo "CImg Library $(SVERSION) : Examples"
@echo "-----------------------------"
@echo " > linux : Linux/BSD target, X11 display, optimizations disabled."
@echo " > dlinux : Linux/BSD target, X11 display, debug mode."
@echo " > olinux : Linux/BSD target, X11 display, optimizations enabled."
@echo " > mlinux : Linus/BSD target, no display, minimal features, optimizations enabled."
@echo " > Mlinux : Linux/BSD target, X11 display, maximal features, optimizations enabled."
@echo
@echo " > macos : MacOS target, X11 display, optimizations disabled."
@echo " > dmacos : MacOS target, X11 display, debug mode."
@echo " > omacos : MacOS target, X11 display, optimizations enabled."
@echo " > mmacos : MacOS target, no display, minimal features, optimizations enabled."
@echo " > Mmacos : MacOS target, X11 display, maximal features, optimizations enabled."
@echo
@echo " > windows : Windows target, GDI32 display, optimizations disabled."
@echo " > dwindows : Windows target, GDI32 display, debug mode."
@echo " > owindows : Windows target, GDI32 display, optimizations enabled."
@echo " > mwindows : Windows target, no display, minimal features, optimizations enabled."
@echo " > Mwindows : Windows target, GDI32 display, maximal features, optimizations enabled."
@echo
@echo " > clean : Clean generated files."
@echo
@echo "Choose your option :"
@read CHOICE; echo; $(MAKE) $$CHOICE; echo; echo "> Next time, you can bypass the menu by typing directly 'make $$CHOICE'"; echo;
all: $(FILES)
clean:
rm -rf *.exe *.o *.obj *~ \#* $(FILES) $(EXTRA_FILES)
ifneq ($(EXE_PRE),)
rm -f $(EXE_PRE)*
endif
# Custom user-defined target
custom:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(VT100_CFLAGS) \
$(TIFF_CFLAGS) \
$(HEIF_CFLAGS) \
$(X11_CFLAGS) \
$(LAPACK_CFLAGS) \
$(XSHM_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(TIFF_LIBS) \
$(HEIF_LIBS) \
$(LAPACK_LIBS) \
$(XSHM_LIBS)" \
all $(EXTRA_FILES)
# Linux/BSD/Mac OSX targets, with X11 display.
#A target for Travis-CI
travis:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS) \
$(FFTW3_CFLAGS) \
$(PNG_CFLAGS) \
$(JPEG_CFLAGS) \
$(ZLIB_CFLAGS) \
$(CURL_CFLAGS) \
$(XSHM_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(FFTW3_LIBS) \
$(PNG_LIBS) \
$(JPEG_LIBS) \
$(ZLIB_LIBS) \
$(CURL_LIBS) \
$(XSHM_LIBS)" \
all
linux:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS) \
$(XSHM_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(XSHM_LIBS)" \
all
dlinux:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(DEBUG_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS) \
$(XSHM_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(XSHM_LIBS)" \
all
olinux:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(OPT_CFLAGS) \
$(OPENMP_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS) \
$(XSHM_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(XSHM_LIBS)" \
"STRIP_EXE=true" \
all
mlinux:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(NODISPLAY_CFLAGS) \
$(OPT_CFLAGS)" \
"STRIP_EXE=true" \
all
Mlinux:
@$(MAKE) \
"CONF_CFLAGS = \
$(OPT_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS) \
$(XSHM_CFLAGS) \
$(XRANDR_CFLAGS) \
$(TIFF_CFLAGS) \
$(HEIF_CFLAGS) \
$(OPENEXR_CFLAGS) \
$(PNG_CFLAGS) \
$(JPEG_CFLAGS) \
$(ZLIB_CFLAGS) \
$(CURL_CFLAGS) \
$(OPENCV_CFLAGS) \
$(MAGICK_CFLAGS) \
$(FFTW3_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(XSHM_LIBS) \
$(XRANDR_LIBS) \
$(TIFF_LIBS) -ltiffxx \
$(HEIF_LIBS) \
$(OPENEXR_LIBS) \
$(PNG_LIBS) \
$(JPEG_LIBS) \
$(ZLIB_LIBS) \
$(CURL_LIBS) \
$(OPENCV_LIBS) \
$(MAGICK_LIBS) \
$(FFTW3_LIBS)" \
"STRIP_EXE=true" \
all $(EXTRA_FILES)
# MacOs targets, with X11 display.
macos:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS)" \
all
dmacos:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(DEBUG_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS)" \
all
omacos:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(OPT_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS)" \
all
mmacos:
@$(MAKE) \
"CONF_CFLAGS = \
$(ANSI_CFLAGS) \
$(NODISPLAY_CFLAGS) \
$(OPT_CFLAGS)" \
all
Mmacos:
@$(MAKE) \
"CONF_CFLAGS = \
$(OPT_CFLAGS) \
$(VT100_CFLAGS) \
$(X11_CFLAGS) \
$(TIFF_CFLAGS) \
$(HEIF_CFLAGS) \
$(MINC2_CFLAGS) \
$(OPENEXR_CFLAGS) \
$(PNG_CFLAGS) \
$(JPEG_CFLAGS) \
$(ZLIB_CFLAGS) \
$(OPENCV_CFLAGS) \
$(MAGICK_CFLAGS) \
$(FFTW3_CFLAGS)" \
"CONF_LIBS = \
$(X11_LIBS) \
$(TIFF_LIBS) \
$(HEIF_LIBS) \
$(MINC2_LIBS) \
$(OPENEXR_LIBS) \
$(PNG_LIBS) \
$(JPEG_LIBS) \
$(ZLIB_LIBS) \
$(OPENCV_LIBS) \
$(MAGICK_LIBS) \
$(FFTW3_LIBS)" \
all $(EXTRA_FILES)
# Windows targets, with GDI32 display.
windows:
@$(MAKE) \
"CONF_CFLAGS = " \
"CONF_LIBS = \
$(GDI32_LIBS)" \
all
dwindows:
@$(MAKE) \
"CONF_CFLAGS = \
$(DEBUG_CFLAGS)" \
"CONF_LIBS = \
$(GDI32_LIBS)" \
all
owindows:
@$(MAKE) \
"CONF_CFLAGS = \
$(OPT_CFLAGS)" \
"CONF_LIBS = \
$(GDI32_LIBS)" \
"STRIP_EXE=true" \
all
mwindows:
@$(MAKE) \
"CONF_CFLAGS = \
$(NODISPLAY_CFLAGS) \
$(OPT_CFLAGS)" \
"STRIP_EXE=true" \
all
Mwindows:
@$(MAKE) \
"CONF_CFLAGS = \
$(OPT_CFLAGS) \
$(TIFF_CFLAGS) \
$(HEIF_CFLAGS) \
$(PNG_CFLAGS) \
$(JPEG_CFLAGS) \
$(ZLIB_CFLAGS) \
$(OPENCV_CFLAGS) \
$(FFTW3_CFLAGS)" \
"CONF_LIBS = \
$(GDI32_LIBS) \
$(TIFF_LIBS) \
$(HEIF_LIBS) \
$(PNG_LIBS) \
$(JPEG_LIBS) \
$(ZLIB_LIBS) \
$(OPENCV_LIBS) \
$(FFTW3_LIBS)" \
"STRIP_EXE=true" \
all $(EXTRA_FILES)
# End of makefile

163
examples/captcha.cpp Normal file
View file

@ -0,0 +1,163 @@
/*
#
# File : captcha.cpp
# ( C++ source file )
#
# Description : Captcha images generator.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#ifndef cimg_debug
#define cimg_debug 1
#endif
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line parameters
//------------------------------
cimg_usage("Simple captcha generator.");
const char *file_o = cimg_option("-o",(const char*)0,"Output image file");
const bool add_border = cimg_option("-b",true,"Add border to captcha image");
const bool visu = cimg_option("-visu",true,"Enable visualization if no output file");
// Generate captcha text (6 char max).
//------------------------------------
const char *predef_words[] = {
"aarrgh", "abacas", "abacus", "abakas", "abamps", "abased", "abaser", "abases", "abasia", "abated", "abater",
"abates", "abatis", "abator", "baobab", "barbal", "barbed", "barbel", "barber", "barbes", "barbet", "barbie",
"barbut", "barcas", "barded", "bardes", "bardic", "barege", "cavies", "cavils", "caving", "cavity", "cavort",
"cawing", "cayman", "cayuse", "ceased", "ceases", "cebids", "ceboid", "cecity", "cedarn", "dicast", "dicers",
"dicier", "dicing", "dicker", "dickey", "dickie", "dicots", "dictum", "didact", "diddle", "diddly", "didies",
"didoes", "emails", "embalm", "embank", "embark", "embars", "embays", "embeds", "embers", "emblem", "embody",
"emboli", "emboly", "embosk", "emboss", "fluffy", "fluids", "fluish", "fluked", "flukes", "flukey", "flumed",
"flumes", "flumps", "flunks", "flunky", "fluors", "flurry", "fluted", "genome", "genoms", "genres", "genros",
"gentes", "gentil", "gentle", "gently", "gentry", "geodes", "geodic", "geoids", "gerahs", "gerbil", "hotter",
"hottie", "houdah", "hounds", "houris", "hourly", "housed", "housel", "houser", "houses", "hovels", "hovers",
"howdah", "howdie", "inland", "inlays", "inlets", "inlier", "inmate", "inmesh", "inmost", "innage", "innate",
"inners", "inning", "inpour", "inputs", "inroad", "joypop", "jubbah", "jubhah", "jubile", "judder", "judged",
"judger", "judges", "judoka", "jugate", "jugful", "jugged", "juggle", "jugula", "knifer", "knifes", "knight",
"knives", "knobby", "knocks", "knolls", "knolly", "knosps", "knotty", "knouts", "knower", "knowns", "knubby",
"legate", "legato", "legend", "legers", "legged", "leggin", "legion", "legist", "legits", "legman", "legmen",
"legong", "legume", "lehuas", "mammal", "mammas", "mammee", "mammer", "mammet", "mammey", "mammie", "mammon",
"mamzer", "manage", "manana", "manats", "manche", "manege", "nihils", "nilgai", "nilgau", "nilled", "nimble",
"nimbly", "nimbus", "nimmed", "nimrod", "ninety", "ninjas", "ninons", "ninths", "niobic", "offish", "offkey",
"offset", "oftest", "ogdoad", "oghams", "ogival", "ogives", "oglers", "ogling", "ogress", "ogrish", "ogrism",
"ohmage", "papaws", "papaya", "papers", "papery", "pappus", "papula", "papule", "papyri", "parade", "paramo",
"parang", "paraph", "parcel", "pardah", "quasar", "quatre", "quaver", "qubits", "qubyte", "queans", "queasy",
"queazy", "queens", "queers", "quelea", "quells", "quench", "querns", "raised", "raiser", "raises", "raisin",
"raitas", "rajahs", "rakees", "rakers", "raking", "rakish", "rallye", "ralphs", "ramada", "ramate", "savory",
"savour", "savoys", "sawers", "sawfly", "sawing", "sawlog", "sawney", "sawyer", "saxony", "sayeds", "sayers",
"sayest", "sayids", "tondos", "toneme", "toners", "tongas", "tonged", "tonger", "tongue", "tonics", "tonier",
"toning", "tonish", "tonlet", "tonner", "tonnes", "uredia", "uredos", "ureide", "uremia", "uremic", "ureter",
"uretic", "urgent", "urgers", "urging", "urials", "urinal", "urines", "uropod", "villus", "vimina", "vinals",
"vincas", "vineal", "vinery", "vinier", "vinify", "vining", "vinous", "vinyls", "violas", "violet", "violin",
"webfed", "weblog", "wechts", "wedded", "wedder", "wedeln", "wedels", "wedged", "wedges", "wedgie", "weeded",
"weeder", "weekly", "weened", "xystoi", "xystos", "xystus", "yabber", "yabbie", "yachts", "yacked", "yaffed",
"yagers", "yahoos", "yairds", "yakked", "yakker", "yakuza", "zigged", "zigzag", "zillah", "zinced", "zincic",
"zincky", "zinebs", "zinged", "zinger", "zinnia", "zipped", "zipper", "zirams", "zircon" };
cimg::srand();
const char *const captcha_text = predef_words[std::rand()%(sizeof(predef_words)/sizeof(char*))];
// Create captcha image
//----------------------
// Write colored and distorted text
CImg<unsigned char> captcha(256,64,1,3,0), color(3);
char letter[2] = { 0 };
for (unsigned int k = 0; k<6; ++k) {
CImg<unsigned char> tmp;
*letter = captcha_text[k];
if (*letter) {
cimg_forX(color,i) color[i] = (unsigned char)(128 + (std::rand()%127));
tmp.draw_text((int)(2 + 8*cimg::rand()),
(int)(12*cimg::rand()),
letter,color.data(),0,1,std::rand()%2?38:57).resize(-100,-100,1,3);
const unsigned int dir = std::rand()%4, wph = tmp.width() + tmp.height();
cimg_forXYC(tmp,x,y,v) {
const int val = dir==0?x + y:(dir==1?x + tmp.height() - y:(dir==2?y + tmp.width() - x:
tmp.width() - x + tmp.height() - y));
tmp(x,y,v) = (unsigned char)std::max(0.0f,std::min(255.0f,1.5f*tmp(x,y,v)*val/wph));
}
if (std::rand()%2) tmp = (tmp.get_dilate(3)-=tmp);
tmp.blur((float)cimg::rand()*0.8f).normalize(0,255);
const float sin_offset = (float)cimg::rand(-1,1)*3, sin_freq = (float)cimg::rand(-1,1)/7;
cimg_forYC(captcha,y,v) captcha.get_shared_row(y,0,v).shift((int)(4*std::cos(y*sin_freq + sin_offset)));
captcha.draw_image(6 + 40*k,tmp);
}
}
// Add geometric and random noise
CImg<unsigned char> copy = (+captcha).fill(0);
for (unsigned int l = 0; l<3; ++l) {
if (l) copy.blur(0.5f).normalize(0,148);
for (unsigned int k = 0; k<10; ++k) {
cimg_forX(color,i) color[i] = (unsigned char)(128 + cimg::rand()*127);
if (cimg::rand()<0.5f) copy.draw_circle((int)(cimg::rand()*captcha.width()),
(int)(cimg::rand()*captcha.height()),
(int)(cimg::rand()*30),
color.data(),0.6f,~0U);
else copy.draw_line((int)(cimg::rand()*captcha.width()),
(int)(cimg::rand()*captcha.height()),
(int)(cimg::rand()*captcha.width()),
(int)(cimg::rand()*captcha.height()),
color.data(),0.6f);
}
}
captcha|=copy;
captcha.noise(10,2);
if (add_border)
captcha.draw_rectangle(0,0,captcha.width() - 1,captcha.height() - 1,
CImg<unsigned char>::vector(255,255,255).data(),1.0f,~0U);
captcha = (+captcha).fill(255) - captcha;
// Write output image and captcha text
//-------------------------------------
std::printf("%s\n",captcha_text);
if (file_o) captcha.save(file_o);
else if (visu) {
CImgDisplay disp(CImg<unsigned char>(512,128,1,3,180).draw_image(128,32,captcha),captcha_text,0);
while (!disp.is_closed() && !disp.key()) { disp.wait(); if (disp.is_resized()) disp.resize(disp).wait(100); }
}
return 0;
}

356
examples/curve_editor2d.cpp Normal file
View file

@ -0,0 +1,356 @@
/*
#
# File : curve_editor2d.cpp
# ( C++ source file )
#
# Description : A simple user interface to construct 2D spline curves.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
# Antonio Albiol Colomer
# ( http://personales.upv.es/~aalbiol/index-english.html )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Compute distance from a point to a segment.
//---------------------------------------------
float dist_segment(const float x, const float y, const float x1, const float y1, const float x2, const float y2) {
const float
dx = x2 - x1,
dy = y2 - y1,
long_segment = (float)std::sqrt(dx*dx + dy*dy);
if (long_segment==0) { const float ddx = x - x1, ddy = y - y1; return (float)std::sqrt(ddx*ddx + ddy*ddy); }
const float
unitx = dx/long_segment,
unity = dy/long_segment,
vx = x - x1,
vy = y - y1,
long_proy = vx*unitx + vy*unity,
proyx = x1 + long_proy*unitx,
proyy = y1 + long_proy*unity;
if (long_proy>long_segment) { const float ddx = x - x2, ddy = y - y2; return std::sqrt(ddx*ddx + ddy*ddy); }
else if (long_proy<0) { const float ddx = x - x1, ddy = y - y1; return std::sqrt(ddx*ddx + ddy*ddy); }
const float ddx = x - proyx, ddy = y - proyy;
return std::sqrt(ddx*ddx + ddy*ddy);
}
// Main procedure
//---------------
int main(int argc, char **argv) {
// Read command line parameters
//-----------------------------
cimg_usage("2D Spline Curve Editor");
const char *file_i = cimg_option("-i",(char*)0,"Input image");
const float contrast = cimg_option("-contrast",0.6f,"Image contrast");
const char *file_ip = cimg_option("-ip",(char*)0,"Input control points");
const char *file_oc = cimg_option("-oc",(char*)0,"Output curve points");
const char *file_op = cimg_option("-op",(char*)0,"Output control points");
const char *file_od = cimg_option("-od",(char*)0,"Output distance function");
bool interp = cimg_option("-poly",true,"Use polynomial interpolation");
bool closed = cimg_option("-closed",true,"Closed curve");
bool show_tangents = cimg_option("-tangents",false,"Show tangents");
bool show_points = cimg_option("-points",true,"Show control points");
bool show_outline = cimg_option("-outline",true,"Show polygon outline");
bool show_indices = cimg_option("-indices",true,"Show points indices");
bool show_coordinates = cimg_option("-coords",false,"Show points coordinates");
const float precision = cimg_option("-prec",0.05f,"Precision of curve discretization");
// Init image data
//-----------------
const unsigned char yellow[] = { 255,255,0 }, white[] = { 255,255,255 }, green[] = { 0,255,0 },
blue[] = { 120,200,255 }, purple[] = { 255,100,255 }, black[] = { 0,0,0 };
CImg<unsigned char> img0, img, help_img;
if (file_i) {
std::fprintf(stderr,"\n - Load input image '%s' : ",cimg::basename(file_i));
img0 = CImg<>(file_i).normalize(0,255.0f*contrast);
std::fprintf(stderr,"Size = %dx%dx%dx%d \n",img0.width(),img0.height(),img0.depth(),img0.spectrum());
img0.resize(-100,-100,1,3);
}
else {
std::fprintf(stderr,"\n - No input image specified, use default 512x512 image.\n");
img0.assign(512,512,1,3,0).draw_grid(32,32,0,0,false,false,green,0.4f,0xCCCCCCCC,0xCCCCCCCC);
}
help_img.assign(220,210,1,3,0).
draw_text(5,5,
"------------------------------------------\n"
"2D Curve Editor\n"
"------------------------------------------\n"
"Left button : Create or move control point\n"
"Right button : Delete control point\n"
"Spacebar : Switch interpolation\n"
"Key 'C' : Switch open/closed mode\n"
"Key 'T' : Show/hide tangents\n"
"Key 'P' : Show/hide control points\n"
"Key 'O' : Show/hide polygon outline\n"
"Key 'N' : Show/hide points indices\n"
"Key 'X' : Show/hide points coordinates\n"
"Key 'H' : Show/hide this help\n"
"Key 'S' : Save control points\n"
"Key 'R' : Reset curve\n",
green);
CImgDisplay disp(img0,"2D Curve Editor",0);
CImgList<float> points, curve;
bool moving = false, help = !file_i;
if (file_ip) {
std::fprintf(stderr," - Load input control points '%s' : ",cimg::basename(file_ip));
points = CImg<>(file_ip).transpose()<'x';
std::fprintf(stderr," %u points\n",points.size());
}
// Enter interactive loop
//------------------------
while (!disp.is_closed() && !disp.is_keyESC() && !disp.is_keyQ()) {
// Handle mouse manipulation
//---------------------------
const unsigned int button = disp.button();
const float
mx = disp.mouse_x()*(float)img0.width()/disp.width(),
my = disp.mouse_y()*(float)img0.height()/disp.height();
if (points && button && mx>=0 && my>=0) {
// Find nearest point and nearest segment
float dmin_pt = cimg::type<float>::max(), dmin_seg = dmin_pt;
unsigned int p_pt = 0, p_seg = 0;
cimglist_for(points,p) {
const unsigned int
pnext = closed?(p + 1)%points.size():(p + 1<(int)points.size()?p + 1:p);
const float
xp = points(p,0),
yp = points(p,1);
const float
d_pt = (xp - mx)*(xp - mx) + (yp - my)*(yp - my),
d_seg = dist_segment(mx,my,xp,yp,points(pnext,0),points(pnext,1));
if (d_pt<dmin_pt) { dmin_pt = d_pt; p_pt = p; }
if (d_seg<dmin_seg) { dmin_seg = d_seg; p_seg = p; }
}
// Handle button
if (button&1) {
if (dmin_pt<100 || moving) { points(p_pt,0) = mx; points(p_pt,1) = my; }
else points.insert(CImg<>::vector(mx,my),p_seg + 1);
moving = true;
}
if (button&2 && dmin_pt<100) {
if (points.size()>3) points.remove(p_pt);
disp.set_button();
}
}
if (!button) moving = false;
if (disp.key()) {
switch (disp.key()) {
case cimg::keySPACE : interp = !interp; break;
case cimg::keyC : closed = !closed; break;
case cimg::keyT : show_tangents = !show_tangents; break;
case cimg::keyP : show_points = !show_points; break;
case cimg::keyO : show_outline = !show_outline; break;
case cimg::keyN : show_indices = !show_indices; break;
case cimg::keyX : show_coordinates = !show_coordinates; break;
case cimg::keyR : points.assign(); break;
case cimg::keyH : help = !help; break;
case cimg::keyS : {
const char *filename = file_op?file_op:"curve_points.dlm";
std::fprintf(stderr," - Save control points in '%s'\n",filename);
(points>'x').transpose().save(filename);
} break;
}
disp.set_key();
}
// Init list of points if empty
//------------------------------
if (!points) {
const float
x0 = img0.width()/4.0f,
y0 = img0.height()/4.0f,
x1 = img0.width() - x0,
y1 = img0.height() - y0;
points.insert(CImg<>::vector(x0,y0)).
insert(CImg<>::vector(x1,y0)).
insert(CImg<>::vector(x1,y1)).
insert(CImg<>::vector(x0,y1));
}
// Estimate curve tangents
//-------------------------
CImg<> tangents(points.size(),2);
cimglist_for(points,p) {
const unsigned int
p0 = closed?(p + points.size() - 1)%points.size():(p?p - 1:0),
p1 = closed?(p + 1)%points.size():(p + 1<(int)points.size()?p + 1:p);
const float
x = points(p,0),
y = points(p,1),
x0 = points(p0,0),
y0 = points(p0,1),
x1 = points(p1,0),
y1 = points(p1,1),
u0 = x - x0,
v0 = y - y0,
n0 = 1e-8f + (float)std::sqrt(u0*u0 + v0*v0),
u1 = x1 - x,
v1 = y1 - y,
n1 = 1e-8f + (float)std::sqrt(u1*u1 + v1*v1),
u = u0/n0 + u1/n1,
v = v0/n0 + v1/n1,
n = 1e-8f + (float)std::sqrt(u*u + v*v),
fact = 0.5f*(n0 + n1);
tangents(p,0) = fact*u/n;
tangents(p,1) = fact*v/n;
}
// Estimate 3th-order polynomial interpolation
//---------------------------------------------
curve.assign();
const unsigned int pmax = points.size() - (closed?0:1);
for (unsigned int p0 = 0; p0<pmax; p0++) {
const unsigned int
p1 = closed?(p0 + 1)%points.size():(p0 + 1<points.size()?p0 + 1:p0);
const float
x0 = points(p0,0),
y0 = points(p0,1),
x1 = points(p1,0),
y1 = points(p1,1);
float ax = 0, bx = 0, cx = 0, dx = 0, ay = 0, by = 0, cy = 0, dy = 0;
if (interp) {
const float
u0 = tangents(p0,0),
v0 = tangents(p0,1),
u1 = tangents(p1,0),
v1 = tangents(p1,1);
ax = 2*(x0 - x1) + u0 + u1;
bx = 3*(x1 - x0) - 2*u0 - u1;
cx = u0;
dx = x0;
ay = 2*(y0 - y1) + v0 + v1;
by = 3*(y1 - y0) - 2*v0 - v1;
cy = v0;
dy = y0;
} else {
ax = ay = bx = by = 0;
dx = x0;
dy = y0;
cx = x1 - x0;
cy = y1 - y0;
}
const float tmax = 1 + precision;
for (float t = 0; t<tmax; t+=precision) {
const float
xt = ax*t*t*t + bx*t*t + cx*t + dx,
yt = ay*t*t*t + by*t*t + cy*t + dy;
curve.insert(CImg<>::vector(xt,yt));
}
}
// Draw curve and display image
//-------------------------------
const float
factx = (float)disp.width()/img0.width(),
facty = (float)disp.height()/img0.height();
img = img0.get_resize(disp.width(),disp.height());
if (help) img.draw_image(help_img,0.6f);
if (interp && show_outline) {
CImg<> npoints = points>'x';
npoints.get_shared_row(0)*=factx;
npoints.get_shared_row(1)*=facty;
img.draw_polygon(npoints,blue,0.4f);
if (closed) img.draw_polygon(npoints,yellow,0.8f,0x11111111);
else img.draw_line(npoints,yellow,0.8f,0x11111111);
}
CImg<> ncurve = curve>'x';
ncurve.get_shared_row(0)*=factx;
ncurve.get_shared_row(1)*=facty;
if (closed) img.draw_polygon(ncurve,white,1.0f,~0U);
else img.draw_line(ncurve,white);
if (show_points) cimglist_for(points,p) {
const float
x = points(p,0)*factx,
y = points(p,1)*facty;
if (show_tangents) {
const float
u = tangents(p,0),
v = tangents(p,1),
n = 1e-8f + (float)std::sqrt(u*u + v*v),
nu = u/n,
nv = v/n;
img.draw_arrow((int)(x - 15*nu),(int)(y - 15*nv),(int)(x + 15*nu),(int)(y + 15*nv),green);
}
if (show_indices) img.draw_text((int)x,(int)(y - 16),"%d",purple,black,1,13,p);
if (show_coordinates)
img.draw_text((int)(x - 24),(int)(y + 8),"(%d,%d)",yellow,black,0.5f,13,(int)points(p,0),(int)points(p,1));
img.draw_circle((int)x,(int)y,3,blue,0.7f);
}
img.display(disp);
disp.wait();
if (disp.is_resized()) disp.resize(false);
}
// Save output result and exit
//-----------------------------
if (file_op) {
std::fprintf(stderr," - Save control points in '%s'\n",cimg::basename(file_op));
(points>'x').transpose().save(file_op);
}
if (file_oc) {
std::fprintf(stderr," - Save curve points in '%s'\n",cimg::basename(file_oc));
(curve>'x').transpose().save(file_oc);
}
if (file_od) {
std::fprintf(stderr," - Computing distance function, please wait...."); std::fflush(stderr);
CImg<> ncurve = (closed?(+curve).insert(curve[0]):curve)>'x';
const float zero = 0.0f, one = 1.0f;
CImg<> distance =
CImg<>(img0.width(),img0.height(),1,1,-1.0f).draw_line(ncurve,&zero).draw_fill(0,0,&one).
distance(0);
std::fprintf(stderr,"\n - Save distance function in '%s'\n",cimg::basename(file_od));
distance.save(file_od);
}
std::fprintf(stderr," - Exit.\n");
std::exit(0);
return 0;
}

563
examples/dtmri_view3d.cpp Normal file
View file

@ -0,0 +1,563 @@
/*
#
# File : dtmri_view3d.cpp
# ( C++ source file )
#
# Description : A viewer of Diffusion-Tensor MRI volumes (medical imaging).
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Compute fractional anisotropy (FA) of a tensor
//-------------------------------------------
template<typename T> float get_FA(const T& val1, const T& val2, const T& val3) {
const float
l1 = val1>0?val1:0, l2 = val2>0?val2:0, l3 = val3>0?val3:0,
lm = (l1 + l2 + l3)/3,
tr2 = 2*(l1*l1 + l2*l2 + l3*l3),
ll1 = l1 - lm,
ll2 = l2 - lm,
ll3 = l3 - lm;
if (tr2>0) return (float)std::sqrt(3*(ll1*ll1 + ll2*ll2 + ll3*ll3)/tr2);
return 0;
}
// Insert an ellipsoid in a CImg 3D scene
//----------------------------------------
template<typename t, typename tp, typename tf, typename tc>
void insert_ellipsoid(const CImg<t>& tensor, const float X, const float Y, const float Z, const float tfact,
const float vx, const float vy, const float vz,
CImgList<tp>& points, CImgList<tf>& faces, CImgList<tc>& colors,
const unsigned int res1=20, const unsigned int res2=20) {
// Compute eigen elements
float l1 = tensor[0], l2 = tensor[1], l3 = tensor[2], fa = get_FA(l1,l2,l3);
CImg<> vec = CImg<>::matrix(tensor[3],tensor[6],tensor[9],
tensor[4],tensor[7],tensor[10],
tensor[5],tensor[8],tensor[11]);
const int
r = (int)std::min(30 + 1.5f*cimg::abs(255*fa*tensor[3]),255.0f),
g = (int)std::min(30 + 1.5f*cimg::abs(255*fa*tensor[4]),255.0f),
b = (int)std::min(30 + 1.5f*cimg::abs(255*fa*tensor[5]),255.0f);
// Define mesh points
const unsigned int N0 = points.size();
for (unsigned int v = 1; v<res2; v++)
for (unsigned int u = 0; u<res1; u++) {
const float
alpha = (float)(u*2*cimg::PI/res1),
beta = (float)(-cimg::PI/2 + v*cimg::PI/res2),
x = (float)(tfact*l1*std::cos(beta)*std::cos(alpha)),
y = (float)(tfact*l2*std::cos(beta)*std::sin(alpha)),
z = (float)(tfact*l3*std::sin(beta));
points.insert((CImg<tp>::vector(X,Y,Z) + vec*CImg<tp>::vector(x,y,z)).mul(CImg<tp>::vector(vx,vy,vz)));
}
const unsigned int N1 = points.size();
points.insert((CImg<tp>::vector(X,Y,Z) - vec*CImg<tp>::vector(0,0,l3*tfact)));
points.insert((CImg<tp>::vector(X,Y,Z) + vec*CImg<tp>::vector(0,0,l3*tfact)));
points[points.size() - 2](0)*=vx; points[points.size() - 2](1)*=vy; points[points.size() - 2](2)*=vz;
points[points.size() - 1](0)*=vx; points[points.size() - 1](1)*=vy; points[points.size() - 1](2)*=vz;
// Define mesh triangles
for (unsigned int vv = 0; vv<res2 - 2; ++vv)
for (unsigned int uu = 0; uu<res1; ++uu) {
const int nv = (vv + 1)%(res2 - 1), nu = (uu + 1)%res1;
faces.insert(CImg<tf>::vector(N0 + res1*vv + nu,N0 + res1*nv + uu,N0 + res1*vv + uu));
faces.insert(CImg<tf>::vector(N0 + res1*vv + nu,N0 + res1*nv + nu,N0 + res1*nv + uu));
colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
}
for (unsigned int uu = 0; uu<res1; ++uu) {
const int nu = (uu + 1)%res1;
faces.insert(CImg<tf>::vector(N0 + nu,N0 + uu,N1));
faces.insert(CImg<tf>::vector(N0 + res1*(res2 - 2) + nu, N1 + 1,N0 + res1*(res2 - 2) + uu));
colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
}
}
// Insert a fiber in a CImg 3D scene
//-----------------------------------
template<typename T,typename te,typename tp, typename tf, typename tc>
void insert_fiber(const CImg<T>& fiber, const CImg<te>& eigen, const CImg<tc>& palette,
const int xm, const int ym, const int zm,
const float vx, const float vy, const float vz,
CImgList<tp>& points, CImgList<tf>& primitives, CImgList<tc>& colors) {
const int N0 = points.size();
float x0 = fiber(0,0), y0 = fiber(0,1), z0 = fiber(0,2), fa0 = eigen.linear_atXYZ(x0,y0,z0,12);
points.insert(CImg<>::vector(vx*(x0 -xm),vy*(y0 - ym),vz*(z0 - zm)));
for (int l = 1; l<fiber.width(); ++l) {
float x1 = fiber(l,0), y1 = fiber(l,1), z1 = fiber(l,2), fa1 = eigen.linear_atXYZ(x1,y1,z1,12);
points.insert(CImg<tp>::vector(vx*(x1 - xm),vy*(y1 - ym),vz*(z1 - zm)));
primitives.insert(CImg<tf>::vector(N0 + l - 1,N0 + l));
const unsigned char
icol = (unsigned char)(fa0*255),
r = palette(icol,0),
g = palette(icol,1),
b = palette(icol,2);
colors.insert(CImg<unsigned char>::vector(r,g,b));
x0 = x1; y0 = y1; z0 = z1; fa0 = fa1;
}
}
// Compute fiber tracking using 4th-order Runge Kutta integration
//-----------------------------------------------------------------
template<typename T>
CImg<> get_fibertrack(CImg<T>& eigen,
const int X0, const int Y0, const int Z0, const float lmax=100,
const float dl=0.1f, const float FAmin=0.7f, const float cmin=0.5f) {
#define align_eigen(i,j,k) \
{ T &u = eigen(i,j,k,3), &v = eigen(i,j,k,4), &w = eigen(i,j,k,5); \
if (u*cu + v*cv + w*cw<0) { u=-u; v=-v; w=-w; }}
CImgList<> resf;
// Forward tracking
float normU = 0, normpU = 0, l = 0, X = (float)X0, Y = (float)Y0, Z = (float)Z0;
T
pu = eigen(X0,Y0,Z0,3),
pv = eigen(X0,Y0,Z0,4),
pw = eigen(X0,Y0,Z0,5);
normpU = (float)std::sqrt(pu*pu + pv*pv + pw*pw);
bool stopflag = false;
while (!stopflag) {
if (X<0 || X>eigen.width() - 1 || Y<0 || Y>eigen.height() - 1 || Z<0 || Z>eigen.depth() - 1 ||
eigen((int)X,(int)Y,(int)Z,12)<FAmin || l>lmax) stopflag = true;
else {
resf.insert(CImg<>::vector(X,Y,Z));
const int
cx = (int)X, px = (cx - 1<0)?0:cx - 1, nx = (cx + 1>=eigen.width())?eigen.width() - 1:cx + 1,
cy = (int)Y, py = (cy - 1<0)?0:cy - 1, ny = (cy + 1>=eigen.height())?eigen.height() - 1:cy + 1,
cz = (int)Z, pz = (cz - 1<0)?0:cz - 1, nz = (cz + 1>=eigen.depth())?eigen.depth() - 1:cz + 1;
const T cu = eigen(cx,cy,cz,3), cv = eigen(cx,cy,cz,4), cw = eigen(cx,cy,cz,5);
align_eigen(px,py,pz); align_eigen(cx,py,pz); align_eigen(nx,py,pz);
align_eigen(px,cy,pz); align_eigen(cx,cy,pz); align_eigen(nx,cy,pz);
align_eigen(px,ny,pz); align_eigen(cx,ny,pz); align_eigen(nx,ny,pz);
align_eigen(px,py,cz); align_eigen(cx,py,cz); align_eigen(nx,py,cz);
align_eigen(px,cy,cz); align_eigen(nx,cy,cz);
align_eigen(px,ny,cz); align_eigen(cx,ny,cz); align_eigen(nx,ny,cz);
align_eigen(px,py,nz); align_eigen(cx,py,nz); align_eigen(nx,py,nz);
align_eigen(px,cy,nz); align_eigen(cx,cy,nz); align_eigen(nx,cy,nz);
align_eigen(px,ny,nz); align_eigen(cx,ny,nz); align_eigen(nx,ny,nz);
const T
u0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,3),
v0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,4),
w0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,5),
u1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,3),
v1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,4),
w1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,5),
u2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,3),
v2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,4),
w2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,5),
u3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,3),
v3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,4),
w3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,5);
T
u = u0/3 + 2*u1/3 + 2*u2/3 + u3/3,
v = v0/3 + 2*v1/3 + 2*v2/3 + v3/3,
w = w0/3 + 2*w1/3 + 2*w2/3 + w3/3;
if (u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
normU = (float)std::sqrt(u*u + v*v + w*w);
const float scal = (u*pu + v*pv + w*pw)/(normU*normpU);
if (scal<cmin) stopflag=true;
X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
normpU = normU;
l+=dl;
}
}
// Backward tracking
l = dl; X = (float)X0; Y = (float)Y0; Z = (float)Z0;
pu = eigen(X0,Y0,Z0,3);
pv = eigen(X0,Y0,Z0,4);
pw = eigen(X0,Y0,Z0,5);
normpU = (float)std::sqrt(pu*pu + pv*pv + pw*pw);
stopflag = false;
while (!stopflag) {
if (X<0 || X>eigen.width() - 1 || Y<0 || Y>eigen.height() - 1 || Z<0 || Z>eigen.depth() - 1 ||
eigen((int)X,(int)Y,(int)Z,12)<FAmin || l>lmax) stopflag = true;
else {
const int
cx = (int)X, px = (cx - 1<0)?0:cx - 1, nx = (cx + 1>=eigen.width())?eigen.width() - 1:cx + 1,
cy = (int)Y, py = (cy - 1<0)?0:cy - 1, ny = (cy + 1>=eigen.height())?eigen.height() - 1:cy + 1,
cz = (int)Z, pz = (cz - 1<0)?0:cz - 1, nz = (cz + 1>=eigen.depth())?eigen.depth() - 1:cz + 1;
const T cu = eigen(cx,cy,cz,3), cv = eigen(cx,cy,cz,4), cw = eigen(cx,cy,cz,5);
align_eigen(px,py,pz); align_eigen(cx,py,pz); align_eigen(nx,py,pz);
align_eigen(px,cy,pz); align_eigen(cx,cy,pz); align_eigen(nx,cy,pz);
align_eigen(px,ny,pz); align_eigen(cx,ny,pz); align_eigen(nx,ny,pz);
align_eigen(px,py,cz); align_eigen(cx,py,cz); align_eigen(nx,py,cz);
align_eigen(px,cy,cz); align_eigen(nx,cy,cz);
align_eigen(px,ny,cz); align_eigen(cx,ny,cz); align_eigen(nx,ny,cz);
align_eigen(px,py,nz); align_eigen(cx,py,nz); align_eigen(nx,py,nz);
align_eigen(px,cy,nz); align_eigen(cx,cy,nz); align_eigen(nx,cy,nz);
align_eigen(px,ny,nz); align_eigen(cx,ny,nz); align_eigen(nx,ny,nz);
const T
u0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,3),
v0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,4),
w0 = 0.5f*dl*eigen.linear_atXYZ(X,Y,Z,5),
u1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,3),
v1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,4),
w1 = 0.5f*dl*eigen.linear_atXYZ(X + u0,Y + v0,Z + w0,5),
u2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,3),
v2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,4),
w2 = 0.5f*dl*eigen.linear_atXYZ(X + u1,Y + v1,Z + w1,5),
u3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,3),
v3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,4),
w3 = 0.5f*dl*eigen.linear_atXYZ(X + u2,Y + v2,Z + w2,5);
T
u = u0/3 + 2*u1/3 + 2*u2/3 + u3/3,
v = v0/3 + 2*v1/3 + 2*v2/3 + v3/3,
w = w0/3 + 2*w1/3 + 2*w2/3 + w3/3;
if (u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; }
normU = (float)std::sqrt(u*u + v*v + w*w);
const float scal = (u*pu + v*pv + w*pw)/(normU*normpU);
if (scal<cmin) stopflag=true;
X-=(pu=u); Y-=(pv=v); Z-=(pw=w);
normpU=normU;
l+=dl;
resf.insert(CImg<>::vector(X,Y,Z),0);
}
}
return resf>'x';
}
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read and init data
//--------------------
cimg_usage("A viewer of Diffusion-Tensor MRI volumes.");
const char *file_i = cimg_option("-i",(char*)0,"Input : Filename of tensor field (volume wxhxdx6)");
const char* vsize = cimg_option("-vsize","1x1x1","Input : Voxel aspect");
const bool normalize = cimg_option("-normalize",true,"Input : Enable tensor normalization");
const char *file_f = cimg_option("-f",(char*)0,"Input : Input fibers\n");
const float dl = cimg_option("-dl",0.5f,"Fiber computation : Integration step");
const float famin = cimg_option("-famin",0.3f,"Fiber computation : Fractional Anisotropy threshold");
const float cmin = cimg_option("-cmin",0.2f,"Fiber computation : Curvature threshold");
const float lmin = cimg_option("-lmin",10.0f,"Fiber computation : Minimum length\n");
const float lmax = cimg_option("-lmax",1000.0f,"Fiber computation : Maximum length\n");
const float tfact = cimg_option("-tfact",1.2f,"Display : Tensor size factor");
const char *bgcolor = cimg_option("-bg","0,0,0","Display : Background color");
unsigned int bgr = 0, bgg = 0, bgb = 0;
std::sscanf(bgcolor,"%u%*c%u%*c%u",&bgr,&bgg,&bgb);
CImg<> tensors;
if (file_i) {
std::fprintf(stderr,"\n- Loading tensors '%s'",cimg::basename(file_i));
tensors.load(file_i);
} else {
// Create a synthetic tensor field here
std::fprintf(stderr,"\n- No input files : Creating a synthetic tensor field");
tensors.assign(32,32,32,6);
cimg_forXYZ(tensors,x,y,z) {
const float
u = x - tensors.width()/2.0f,
v = y - tensors.height()/2.0f,
w = z - tensors.depth()/2.0f,
norm = (float)std::sqrt(1e-5f + u*u + v*v + w*w),
nu = u/norm, nv = v/norm, nw = w/norm;
const CImg<>
dir1 = CImg<>::vector(nu,nv,nw),
dir2 = CImg<>::vector(-nv,nu,nw),
dir3 = CImg<>::vector(nw*(nv - nu),-nw*(nu + nv),nu*nu + nv*nv);
tensors.set_tensor_at(2.0*dir1*dir1.get_transpose() +
1.0*dir2*dir2.get_transpose() +
0.7*dir3*dir3.get_transpose(),
x,y,z);
}
}
float voxw = 1, voxh = 1, voxd = 1;
std::sscanf(vsize,"%f%*c%f%*c%f",&voxw,&voxh,&voxd);
std::fprintf(stderr," : %ux%ux%u image, voxsize=%gx%gx%g.",
tensors.width(),tensors.height(),tensors.depth(),
voxw,voxh,voxd);
CImgList<> fibers;
if (file_f) {
std::fprintf(stderr,"\n- Loading fibers '%s'.",cimg::basename(file_f));
fibers.load(file_f);
}
const CImg<unsigned char> fiber_palette =
CImg<>(2,1,1,3).fill(200,255,0,255,0,200).RGBtoHSV().resize(256,1,1,3,3).HSVtoRGB();
// Compute eigen elements
//------------------------
std::fprintf(stderr,"\n- Compute eigen elements.");
CImg<unsigned char> coloredFA(tensors.width(),tensors.height(),tensors.depth(),3);
CImg<> eigen(tensors.width(),tensors.height(),tensors.depth(),13);
CImg<> val,vec;
float eigmax = 0;
cimg_forXYZ(tensors,x,y,z) {
tensors.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
eigen(x,y,z,0) = val[0]; eigen(x,y,z,1) = val[1]; eigen(x,y,z,2) = val[2];
if (val[0]<0) val[0] = 0;
if (val[1]<0) val[1] = 0;
if (val[2]<0) val[2] = 0;
if (val[0]>eigmax) eigmax = val[0];
eigen(x,y,z,3) = vec(0,0); eigen(x,y,z,4) = vec(0,1); eigen(x,y,z,5) = vec(0,2);
eigen(x,y,z,6) = vec(1,0); eigen(x,y,z,7) = vec(1,1); eigen(x,y,z,8) = vec(1,2);
eigen(x,y,z,9) = vec(2,0); eigen(x,y,z,10) = vec(2,1); eigen(x,y,z,11) = vec(2,2);
const float fa = get_FA(val[0],val[1],val[2]);
eigen(x,y,z,12) = fa;
const int
r = (int)std::min(255.0f,1.5f*cimg::abs(255*fa*vec(0,0))),
g = (int)std::min(255.0f,1.5f*cimg::abs(255*fa*vec(0,1))),
b = (int)std::min(255.0f,1.5f*cimg::abs(255*fa*vec(0,2)));
coloredFA(x,y,z,0) = (unsigned char)r;
coloredFA(x,y,z,1) = (unsigned char)g;
coloredFA(x,y,z,2) = (unsigned char)b;
}
tensors.assign();
std::fprintf(stderr,"\n- Maximum diffusivity = %g, Maximum FA = %g",eigmax,eigen.get_shared_channel(12).max());
if (normalize) {
std::fprintf(stderr,"\n- Normalize tensors.");
eigen.get_shared_channels(0,2)/=eigmax;
}
// Init display and begin user interaction
//-----------------------------------------
std::fprintf(stderr,"\n- Open user window.");
CImgDisplay disp(256,256,"DTMRI Viewer",0);
CImgDisplay disp3d(800,600,"3D Local View",0,false,true);
unsigned int XYZ[3];
XYZ[0] = eigen.width()/2; XYZ[1] = eigen.height()/2; XYZ[2] = eigen.depth()/2;
while (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC()) {
const CImg<int> s = coloredFA.get_select(disp,2,XYZ);
if (!disp.is_closed()) switch (disp.key()) {
// Open 3D visualization window
//-----------------------------
case cimg::keyA :
case 0 : {
const unsigned char white[] = { 255 };
disp3d.display(CImg<unsigned char>(disp3d.width(),disp3d.height(),1,1,0).
draw_text(10,10,"Please wait...",white)).show();
int xm, ym, zm, xM, yM, zM;
if (!disp.key()) { xm = s[0]; ym = s[1]; zm = s[2]; xM = s[3]; yM = s[4]; zM = s[5]; }
else { xm = ym = zm = 0; xM = eigen.width() - 1; yM = eigen.height() - 1; zM = eigen.height() - 1; }
const CImg<> img = eigen.get_crop(xm,ym,zm,xM,yM,zM);
CImgList<> points;
CImgList<unsigned int> primitives;
CImgList<unsigned char> colors;
// Add ellipsoids to the 3D scene
int X = img.width()/2, Y = img.height()/2, Z = img.depth()/2;
cimg_forXY(img,x,y)
insert_ellipsoid(img.get_vector_at(x,y,Z),(float)x,(float)y,(float)Z,
tfact,voxw,voxh,voxd,points,primitives,colors,10,6);
cimg_forXZ(img,x,z)
insert_ellipsoid(img.get_vector_at(x,Y,z),(float)x,(float)Y,(float)z,
tfact,voxw,voxh,voxd,points,primitives,colors,10,6);
cimg_forYZ(img,y,z)
insert_ellipsoid(img.get_vector_at(X,y,z),(float)X,(float)y,(float)z,
tfact,voxw,voxh,voxd,points,primitives,colors,10,6);
// Add computed fibers to the 3D scene
const CImg<> veigen = eigen.get_crop(xm,ym,zm,xM,yM,zM);
cimglist_for(fibers,l) {
const CImg<>& fiber = fibers[l];
if (fiber.width()) insert_fiber(fiber,eigen,fiber_palette,
xm,ym,zm,voxw,voxh,voxd,
points,primitives,colors);
}
// Display 3D object
CImg<unsigned char> visu = CImg<unsigned char>(3,disp3d.width(),disp3d.height(),1,0).
fill((unsigned char)bgr,(unsigned char)bgg,(unsigned char)bgb).
permute_axes("yzcx");
bool stopflag = false;
while (!disp3d.is_closed() && !stopflag) {
const CImg<> pts = points>'x';
visu.display_object3d(disp3d,pts,primitives,colors,true,4,-1,false,800,0.05f,1.0f);
disp3d.close();
switch (disp3d.key()) {
case cimg::keyM : { // Create movie
std::fprintf(stderr,"\n- Movie mode.\n");
const unsigned int N = 256;
CImg<> cpts(pts);
const CImg<> x = pts.get_shared_row(0), y = pts.get_shared_row(1), z = pts.get_shared_row(2);
float
_xm, _xM = x.max_min(_xm),
_ym, _yM = y.max_min(_ym),
_zm, _zM = z.max_min(_zm),
ratio = 2.0f*std::min(visu.width(),visu.height())/(3.0f*cimg::max(_xM - _xm,_yM - _ym,_zM - _zm)),
dx = 0.5f*(_xM + _xm), dy = 0.5f*(_yM + _ym), dz = 0.5f*(_zM + _zm);
cimg_forX(pts,l) {
cpts(l,0) = (pts(l,0) - dx)*ratio;
cpts(l,1) = (pts(l,1) - dy)*ratio;
cpts(l,2) = (pts(l,2) - dz)*ratio;
}
for (unsigned int i=0; i<N; i++) {
std::fprintf(stderr,"\r- Frame %u/%u.",i,N);
const float alpha = (float)(i*360/N);
const CImg<> rpts = CImg<>::rotation_matrix(0,1,0,alpha)*CImg<>::rotation_matrix(1,0,0,75)*cpts;
visu.fill(0).draw_object3d(visu.width()/2.0f,visu.height()/2.0f,-500.0f,rpts,primitives,colors,
4,false,800.0f,visu.width()/2.0f,visu.height()/2.0f,-800.0f,0.05f,1.0f).
display(disp3d);
visu.save("frame.png",i);
}
visu.fill(0);
} break;
default: stopflag = true;
}
}
if (disp3d.is_fullscreen()) disp3d.toggle_fullscreen().resize(800,600).close();
} break;
// Compute region statistics
//---------------------------
case cimg::keyR : {
std::fprintf(stderr,"\n- Statistics computation. Select region."); std::fflush(stderr);
const CImg<int> sel = coloredFA.get_select(disp,2,XYZ);
int xm, ym, zm, xM, yM, zM;
if (!disp.key()) { xm = sel[0]; ym = sel[1]; zm = sel[2]; xM = sel[3]; yM = sel[4]; zM = sel[5]; }
else { xm = ym = zm = 0; xM = eigen.width() - 1; yM = eigen.height() - 1; zM = eigen.height() - 1; }
const CImg<> img = eigen.get_crop(xm,ym,zm,xM,yM,zM);
std::fprintf(stderr,"\n- Mean diffusivity = %g, Mean FA = %g\n",
eigen.get_shared_channel(0).mean(),
eigen.get_shared_channel(12).mean());
} break;
// Track fiber bundle (single region)
//----------------------------------
case cimg::keyF : {
std::fprintf(stderr,"\n- Tracking mode (single region). Select starting region.\n"); std::fflush(stderr);
const CImg<int> sel = coloredFA.get_select(disp,2,XYZ);
const unsigned int N = fibers.size();
for (int z = sel[2]; z<=sel[5]; ++z)
for (int y = sel[1]; y<=sel[4]; ++y)
for (int x = sel[0]; x<=sel[3]; ++x) {
const CImg<> fiber = get_fibertrack(eigen,x,y,z,lmax,dl,famin,cmin);
if (fiber.width()>lmin) {
std::fprintf(stderr,"\rFiber %u : Starting from (%d,%d,%d)\t\t",fibers.size(),x,y,z);
fibers.insert(fiber);
}
}
std::fprintf(stderr,"\n- %u fiber(s) added (total %u).",fibers.size() - N,fibers.size());
} break;
// Track fiber bundle (double regions)
//------------------------------------
case cimg::keyG : {
std::fprintf(stderr,"\n- Tracking mode (double region). Select starting region."); std::fflush(stderr);
const CImg<int> sel = coloredFA.get_select(disp,2,XYZ);
std::fprintf(stderr," Select ending region."); std::fflush(stderr);
const CImg<int> nsel = coloredFA.get_select(disp,2,XYZ);
const unsigned int N = fibers.size();
// Track from start to end
for (int z = sel[2]; z<=sel[5]; ++z)
for (int y = sel[1]; y<=sel[4]; ++y)
for (int x = sel[0]; x<=sel[3]; ++x) {
const CImg<> fiber = get_fibertrack(eigen,x,y,z,lmax,dl,famin,cmin);
if (fiber.width()>lmin) {
bool valid_fiber = false;
cimg_forX(fiber,k) {
const int fx = (int)fiber(k,0), fy = (int)fiber(k,1), fz = (int)fiber(k,2);
if (fx>=nsel[0] && fx<=nsel[3] &&
fy>=nsel[1] && fy<=nsel[4] &&
fz>=nsel[2] && fz<=nsel[5]) valid_fiber = true;
}
if (valid_fiber) fibers.insert(fiber);
}
}
// Track from end to start
for (int z = nsel[2]; z<=nsel[5]; ++z)
for (int y = nsel[1]; y<=nsel[4]; ++y)
for (int x = nsel[0]; x<=nsel[3]; ++x) {
const CImg<> fiber = get_fibertrack(eigen,x,y,z,lmax,dl,famin,cmin);
if (fiber.width()>lmin) {
bool valid_fiber = false;
cimg_forX(fiber,k) {
const int fx = (int)fiber(k,0), fy = (int)fiber(k,1), fz = (int)fiber(k,2);
if (fx>=sel[0] && fx<=sel[3] &&
fy>=sel[1] && fy<=sel[4] &&
fz>=sel[2] && fz<=sel[5]) valid_fiber = true;
}
if (valid_fiber) {
std::fprintf(stderr,"\rFiber %u : Starting from (%d,%d,%d)\t\t",fibers.size(),x,y,z);
fibers.insert(fiber);
}
}
}
std::fprintf(stderr," %u fiber(s) added (total %u).",fibers.size() - N,fibers.size());
} break;
// Clear fiber bundle
//-------------------
case cimg::keyC : {
std::fprintf(stderr,"\n- Fibers removed.");
fibers.assign();
} break;
// Save fibers
//-------------
case cimg::keyS : {
fibers.save("fibers.cimg");
std::fprintf(stderr,"\n- Fibers saved.");
} break;
}
}
std::fprintf(stderr,"\n- Exit.\n\n\n");
return 0;
}

View file

@ -0,0 +1,218 @@
/*
#
# File : edge_explorer2d.cpp
# ( C++ source file )
#
# Description : Real time edge detection while moving a ROI
# (rectangle of interest) over the original image.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Orges Leka
# ( oleka(at)students.uni-mainz.de )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main(int argc, char** argv) {
// Usage of the program displayed at the command line
cimg_usage("Real time edge detection with CImg. (c) Orges Leka");
// Read command line arguments
// With cimg_option we can get a new name for the image which is to be loaded from the command line.
const char* img_name = cimg_option("-i", cimg_imagepath "parrot.ppm","Input image.");
double
alpha = cimg_option("-a",1.0,"Blurring the gradient image."),
thresL = cimg_option("-tl",13.5,"Lower thresholding used in Hysteresis."),
thresH = cimg_option("-th",13.6,"Higher thresholding used in Hysteresis.");
const unsigned int
mode = cimg_option("-m",1,"Detection mode: 1 = Hysteresis, 2 = Gradient angle."),
factor = cimg_option("-s",80,"Half-size of edge-explorer window.");
cimg_help("\nAdditional notes : user can press following keys on main display window :\n"
" - Left arrow : Decrease alpha.\n"
" - Right arrow : Increase alpha.\n");
// Construct a new image called 'edge' of size (2*factor,2*factor)
// and of type 'unsigned char'.
CImg<unsigned char> edge(2*factor,2*factor);
CImgDisplay disp_edge(512,512,"Edge Explorer");
// Load the image with the name 'img_name' into the CImg 'img'.
// and create a display window 'disp' for the image 'img'.
const CImg<unsigned char> img = CImg<float>::get_load(img_name).norm().normalize(0,255);
CImgDisplay disp(img,"Original Image");
// Begin main interaction loop.
int x = 0, y = 0;
bool redraw = false;
while (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC()) {
disp.wait(100);
if (disp.button()&1) { alpha+=0.05; redraw = true; }
if (disp.button()&2) { alpha-=0.05; redraw = true; }
if (disp.wheel()) { alpha+=0.05*disp.wheel(); disp.set_wheel(); redraw = true; }
if (alpha<0) alpha = 0;
if (disp_edge.is_resized()) { disp_edge.resize(); redraw = true; }
if (disp_edge.is_closed()) disp_edge.show();
if (disp.is_resized()) disp.resize(disp);
if (disp.mouse_x()>=0) {
x = disp.mouse_x(); // Getting the current position of the mouse
y = disp.mouse_y(); //
redraw = true; // The image should be redrawn
}
if (redraw) {
disp_edge.set_title("Edge explorer (alpha=%g)",alpha);
const int
x0 = x - factor, y0 = y - factor, // These are the coordinates for the red rectangle
x1 = x + factor, y1 = y + factor; // to be drawn on the original image
const unsigned char
red[3] = { 255,0,0 }, //
black[3] = { 0,0,0 }; // Defining the colors we need for drawing
(+img).draw_rectangle(x0,y0,x1,y1,red,1.0f,0x55555555U).display(disp);
//^ We draw the red rectangle on the original window using 'draw_line'.
// Then we display the result via '.display(disp)' .
// Observe, that the color 'red' has to be of type 'const unsigned char',
// since the image 'img' is of type 'const CImg<unsigned char>'.
//'normalize' is used to get a greyscaled image.
CImg<> visu_bw = CImg<>(img).get_crop(x0,y0,x1,y1).get_norm().normalize(0,255).resize(-100,-100,1,2,2);
// get_crop(x0,y0,x1,y1) gets the rectangle we are interested in.
edge.fill(255); // Background color in the edge-detection window is white
// grad[0] is the gradient image of 'visu_bw' in x-direction.
// grad[1] is the gradient image of 'visu_bw' in y-direction.
CImgList<> grad(visu_bw.blur((float)alpha).normalize(0,255).get_gradient());
// To avoid unnecessary calculations in the image loops:
const double
pi = cimg::PI,
p8 = pi/8.0, p38 = 3.0*p8,
p58 = 5.0*p8, p78 = 7.0*p8;
cimg_forXY(visu_bw,s,t) {
// We take s,t instead of x,y, since x,y are already used.
// s corresponds to the x-ordinate of the pixel while t corresponds to the y-ordinate.
if ( 1 <= s && s <= visu_bw.width() - 1 && 1 <= t && t <=visu_bw.height() - 1) { // if - good points
double
Gs = grad[0](s,t), //
Gt = grad[1](s,t), // The actual pixel is (s,t)
Gst = cimg::abs(Gs) + cimg::abs(Gt), //
// ^-- For efficient computation we observe that |Gs|+ |Gt| ~=~ sqrt( Gs^2 + Gt^2)
Gr, Gur, Gu, Gul, Gl, Gdl, Gd, Gdr;
// ^-- right, up right, up, up left, left, down left, down, down right.
double theta = std::atan2(std::max(1e-8,Gt),Gs) + pi; // theta is from the interval [0,Pi]
switch(mode) {
case 1: // Hysterese is applied
if (Gst>=thresH) { edge.draw_point(s,t,black); }
else if (thresL <= Gst && Gst < thresH) {
// Neighbourhood of the actual pixel:
Gr = cimg::abs(grad[0](s + 1,t)) + cimg::abs(grad[1](s + 1,t)); // right
Gl = cimg::abs(grad[0](s - 1,t)) + cimg::abs(grad[1](s - 1,t)); // left
Gur = cimg::abs(grad[0](s + 1,t + 1)) + cimg::abs(grad[1](s + 1,t + 1)); // up right
Gdl = cimg::abs(grad[0](s - 1,t - 1)) + cimg::abs(grad[1](s - 1,t - 1)); // down left
Gu = cimg::abs(grad[0](s,t + 1)) + cimg::abs(grad[1](s,t + 1)); // up
Gd = cimg::abs(grad[0](s,t - 1)) + cimg::abs(grad[1](s,t - 1)); // down
Gul = cimg::abs(grad[0](s - 1,t + 1)) + cimg::abs(grad[1](s - 1,t + 1)); // up left
Gdr = cimg::abs(grad[0](s + 1,t - 1)) + cimg::abs(grad[1](s + 1,t - 1)); // down right
if (Gr>=thresH || Gur>=thresH || Gu>=thresH || Gul>=thresH
|| Gl>=thresH || Gdl >=thresH || Gu >=thresH || Gdr >=thresH) {
edge.draw_point(s,t,black);
}
};
break;
case 2: // Angle 'theta' of the gradient (Gs,Gt) at the point (s,t)
if(theta >= pi)theta-=pi;
//rounding theta:
if ((p8 < theta && theta <= p38 ) || (p78 < theta && theta <= pi)) {
// See (*) below for explanation of the vocabulary used.
// Direction-pixel is (s + 1,t) with corresponding gradient value Gr.
Gr = cimg::abs(grad[0](s + 1,t)) + cimg::abs(grad[1](s + 1,t)); // right
// Contra-direction-pixel is (s - 1,t) with corresponding gradient value Gl.
Gl = cimg::abs(grad[0](s - 1,t)) + cimg::abs(grad[1](s - 1,t)); // left
if (Gr < Gst && Gl < Gst) {
edge.draw_point(s,t,black);
}
}
else if ( p8 < theta && theta <= p38) {
// Direction-pixel is (s + 1,t + 1) with corresponding gradient value Gur.
Gur = cimg::abs(grad[0](s + 1,t + 1)) + cimg::abs(grad[1](s + 1,t + 1)); // up right
// Contra-direction-pixel is (s-1,t-1) with corresponding gradient value Gdl.
Gdl = cimg::abs(grad[0](s - 1,t - 1)) + cimg::abs(grad[1](s - 1,t - 1)); // down left
if (Gur < Gst && Gdl < Gst) {
edge.draw_point(s,t,black);
}
}
else if ( p38 < theta && theta <= p58) {
// Direction-pixel is (s,t + 1) with corresponding gradient value Gu.
Gu = cimg::abs(grad[0](s,t + 1)) + cimg::abs(grad[1](s,t + 1)); // up
// Contra-direction-pixel is (s,t - 1) with corresponding gradient value Gd.
Gd = cimg::abs(grad[0](s,t - 1)) + cimg::abs(grad[1](s,t - 1)); // down
if (Gu < Gst && Gd < Gst) {
edge.draw_point(s,t,black);
}
}
else if (p58 < theta && theta <= p78) {
// Direction-pixel is (s - 1,t + 1) with corresponding gradient value Gul.
Gul = cimg::abs(grad[0](s - 1,t + 1)) + cimg::abs(grad[1](s - 1,t + 1)); // up left
// Contra-direction-pixel is (s + 1,t - 1) with corresponding gradient value Gdr.
Gdr = cimg::abs(grad[0](s + 1,t - 1)) + cimg::abs(grad[1](s + 1,t - 1)); // down right
if (Gul < Gst && Gdr < Gst) {
edge.draw_point(s,t,black);
}
};
break;
} // switch
} // if good-points
} // cimg_forXY */
edge.display(disp_edge);
}// if redraw
} // while
return 0;
}
// (*) Comments to the vocabulary used:
// If (s,t) is the current pixel, and G=(Gs,Gt) is the gradient at (s,t),
// then the _direction_pixel_ of (s,t) shall be the one of the eight neighbour pixels
// of (s,t) in whose direction the gradient G shows.
// The _contra_direction_pixel is the pixel in the opposite direction in which the gradient G shows.
// The _corresponding_gradient_value_ of the pixel (x,y) with gradient G = (Gx,Gy)
// shall be |Gx| + |Gy| ~=~ sqrt(Gx^2 + Gy^2).

94
examples/fade_images.cpp Normal file
View file

@ -0,0 +1,94 @@
/*
#
# File : fade_images.cpp
# ( C++ source file )
#
# Description : Compute a linear fading between two images.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
#undef min
#undef max
// Main procedure
//---------------
int main(int argc,char **argv) {
// Read and check command line parameters.
cimg_usage("Compute a linear fading between two 2D images");
const char *file_i1 = cimg_option("-i1",cimg_imagepath "sh0r.pgm","Input Image 1");
const char *file_i2 = cimg_option("-i2",cimg_imagepath "milla.bmp","Input Image 2");
const char *file_o = cimg_option("-o",(char*)0,"Output Image");
const bool visu = cimg_option("-visu",true,"Visualization mode");
const double pmin = cimg_option("-min",40.0,"Begin of the fade (in %)")/100.0;
const double pmax = cimg_option("-max",60.0,"End of the fade (in %)")/100.0;
const double angle = cimg_option("-angle",0.0,"Fade angle")*cil::cimg::PI/180;
// Init images.
cil::CImg<unsigned char> img1(file_i1), img2(file_i2);
if (!img2.is_sameXYZC(img1)) {
int
dx = std::max(img1.width(),img2.width()),
dy = std::max(img1.height(),img2.height()),
dz = std::max(img1.depth(),img2.depth()),
dv = std::max(img1.spectrum(),img2.spectrum());
img1.resize(dx,dy,dz,dv,3);
img2.resize(dx,dy,dz,dv,3);
}
cil::CImg<unsigned char> dest(img1);
// Compute the faded image.
const double ca = std::cos(angle), sa = std::sin(angle);
double alpha;
cimg_forXYZC(dest,x,y,z,k) {
const double X = ((double)x/img1.width() - 0.5)*ca + ((double)y/img1.height() - 0.5)*sa;
if (X + 0.5<pmin) alpha = 0; else {
if (X + 0.5>pmax) alpha = 1; else
alpha = (X + 0.5 - pmin)/(pmax - pmin);
}
dest(x,y,z,k) = (unsigned char)((1 - alpha)*img1(x,y,z,k) + alpha*img2(x,y,z,k));
}
// Save and exit
if (file_o) dest.save(file_o);
if (visu) dest.display("Image fading");
return 0;
}

172
examples/gaussian_fit1d.cpp Normal file
View file

@ -0,0 +1,172 @@
/*
#
# File : gaussian_fit1d.cpp
# ( C++ source file )
#
# Description : Fit a gaussian function on a set of sample points,
# using the Levenberg-Marquardt algorithm.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#ifndef cimg_plugin
#define cimg_plugin "examples/gaussian_fit1d.cpp"
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Main procedure
//----------------
int main(int argc,char **argv) {
cimg_usage("Fit gaussian function on sample points, using Levenberg-Marquardt algorithm.");
// Read command line arguments.
const char *s_params = cimg_option("-p","10,3,4","Amplitude, Mean and Std of the ground truth");
const unsigned int s_nb = cimg_option("-N",40,"Number of sample points");
const float s_noise = cimg_option("-n",10.0f,"Pourcentage of noise on the samples points");
const char *s_xrange = cimg_option("-x","-10,10","X-range allowed for the sample points");
const char *f_params = cimg_option("-p0",(char*)0,"Amplitude, Mean and Std of the first estimate");
const float f_lambda0 = cimg_option("-l",100.0f,"Initial damping factor");
const float f_dlambda = cimg_option("-dl",0.9f,"Damping attenuation");
float s_xmin = -10, s_xmax = 10, s_amp = 1, s_mean = 1, s_std = 1;
std::sscanf(s_xrange,"%f%*c%f",&s_xmin,&s_xmax);
std::sscanf(s_params,"%f%*c%f%*c%f",&s_amp,&s_mean,&s_std);
// Create noisy samples of a Gaussian function.
const float s_std2 = 2*s_std*s_std, s_fact = s_amp/((float)std::sqrt(2*cimg::PI)*s_std);
CImg<> samples(s_nb,2);
cimg_forX(samples,i) {
const float
x = (float)(s_xmin + (s_xmax - s_xmin)*cimg::rand()),
y = s_fact*(float)(1 + s_noise*cimg::grand()/100)*std::exp(-cimg::sqr(x - s_mean)/s_std2);
samples(i,0) = x;
samples(i,1) = y;
}
// Fit Gaussian function on the sample points and display curve iterations.
CImgDisplay disp(640,480,"Levenberg-Marquardt Gaussian Fitting",0);
float f_amp = 1, f_mean = 1, f_std = 1, f_lambda = f_lambda0;
if (f_params) std::sscanf(f_params,"%f%*c%f%*c%f",&f_amp,&f_mean,&f_std);
else {
const float& vmax = samples.get_shared_row(1).max();
float cmax = 0; samples.contains(vmax,cmax);
f_mean = samples((int)cmax,0);
f_std = (s_xmax - s_xmin)/10;
f_amp = vmax*(float)std::sqrt(2*cimg::PI)*f_std;
}
CImg<> beta = CImg<>::vector(f_amp,f_mean,f_std);
for (unsigned int iter = 0; !disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC(); ++iter) {
// Do one iteration of the Levenberg-Marquardt algorithm.
CImg<> YmF(1,s_nb), J(beta.height(),s_nb);
const float
_f_amp = beta(0), _f_mean = beta(1), _f_std = beta(2),
_f_std2 = 2*_f_std*_f_std, _f_fact = (float)std::sqrt(2*cimg::PI)*_f_std;
float _f_error = 0;
cimg_forY(J,i) {
const float
x = samples(i,0),
_f_exp = std::exp(-cimg::sqr(x - _f_mean)/_f_std2),
delta = samples(i,1) - _f_amp*_f_exp/_f_fact;
YmF(i) = delta;
J(0,i) = _f_exp/_f_fact;
J(1,i) = _f_amp*_f_exp/_f_fact*(x - _f_mean)*2/_f_std2;
J(2,i) = _f_amp*_f_exp/_f_fact*(cimg::sqr(x - _f_mean)/(_f_std*_f_std*_f_std));
_f_error+=cimg::sqr(delta);
}
CImg<> Jt = J.get_transpose(), M = Jt*J;
cimg_forX(M,x) M(x,x)*=1 + f_lambda;
beta+=M.get_invert()*Jt*YmF;
if (beta(0)<=0) beta(0) = 0.1f;
if (beta(2)<=0) beta(2) = 0.1f;
f_lambda*=f_dlambda;
// Display fitting curves.
const unsigned char black[] = { 0,0,0 }, gray[] = { 228,228,228 };
CImg<unsigned char>(disp.width(),disp.height(),1,3,255).
draw_gaussfit(samples,beta(0),beta(1),beta(2),s_amp,s_mean,s_std).
draw_rectangle(5,7,150,100,gray,0.9f).draw_rectangle(5,7,150,100,black,1,~0U).
draw_text(10,10,"Iteration : %d",black,0,1,13,iter).
draw_text(10,25,"Amplitude : %.4g (%.4g)",black,0,1,13,beta(0),s_amp).
draw_text(10,40,"Mean : %.4g (%.4g)",black,0,1,13,beta(1),s_mean).
draw_text(10,55,"Std : %.4g (%.4g)",black,0,1,13,beta(2),s_std).
draw_text(10,70,"Error : %.4g",black,0,1,13,std::sqrt(_f_error)).
draw_text(10,85,"Lambda : %.4g",black,0,1,13,f_lambda).
display(disp.resize(false).wait(20));
}
return 0;
}
#else
// Draw sample points, ideal and fitted gaussian curves on the instance image.
// (defined as a CImg plug-in function).
template<typename t>
CImg<T>& draw_gaussfit(const CImg<t>& samples,
const float f_amp, const float f_mean, const float f_std,
const float i_amp, const float i_mean, const float i_std) {
if (is_empty()) return *this;
const unsigned char black[] = { 0,0,0 }, green[] = { 10,155,20 }, orange[] = { 155,20,0 }, purple[] = { 200,10,200 };
float
xmin, xmax = samples.get_shared_row(0).max_min(xmin), deltax = xmax - xmin,
ymin, ymax = samples.get_shared_row(1).max_min(ymin), deltay = ymax - ymin;
xmin-=0.2f*deltax; xmax+=0.2f*deltax; ymin-=0.2f*deltay; ymax+=0.2f*deltay;
deltax = xmax - xmin; deltay = ymax - ymin;
draw_grid(64,64,0,0,false,false,black,0.3f,0x55555555,0x55555555).draw_axes(xmin,xmax,ymax,ymin,black,0.8f);
CImg<> nsamples(samples);
(nsamples.get_shared_row(0)-=xmin)*=width()/deltax;
(nsamples.get_shared_row(1)-=ymax)*=-height()/deltay;
cimg_forX(nsamples,i) draw_circle((int)nsamples(i,0),(int)nsamples(i,1),3,orange,1,~0U);
CImg<int> truth(width(),2), fit(width(),2);
const float
i_std2 = 2*i_std*i_std, i_fact = i_amp/((float)std::sqrt(2*cimg::PI)*i_std),
f_std2 = 2*f_std*f_std, f_fact = f_amp/((float)std::sqrt(2*cimg::PI)*f_std);
cimg_forX(*this,x) {
const float
x0 = xmin + x*deltax/width(),
ys0 = i_fact*std::exp(-cimg::sqr(x0 - i_mean)/i_std2),
yf0 = f_fact*std::exp(-cimg::sqr(x0 - f_mean)/f_std2);
fit(x,0) = truth(x,0) = x;
truth(x,1) = (int)((ymax - ys0)*height()/deltay);
fit(x,1) = (int)((ymax - yf0)*height()/deltay);
}
return draw_line(truth,green,0.7f,0xCCCCCCCC).draw_line(fit,purple);
}
#endif

View file

@ -0,0 +1,353 @@
/*
#
# File : generate_loop_macros.cpp
# ( C++ source file )
#
# Description : Generate C++ macros to deal with MxN[xP] neighborhood
# loops within the CImg Library.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
// Generate macro(s) 'cimg_forN(i,bound)'
//----------------------------------------
void generate_forN(const unsigned int N) {
if (N>=2) {
const unsigned int Nn = N/2, Np = Nn - ((N + 1)%2);
std::printf("#define cimg_for%u(bound,i) for (int i = 0, \\\n",N);
for (unsigned int k = 0; k<Np; ++k) std::printf(" _p%u##i = 0,",Np - k);
std::printf(" \\\n");
for (unsigned int k = 1; k<=Nn; ++k)
std::printf(" _n%u##i = %u>=(int)(bound)?(int)(bound) - 1:%u%c \\\n",k,k,k,k==Nn?';':',');
std::printf(" _n%u##i<(int)(bound) || ",Nn);
for (unsigned int k = Nn - 1; k>=1; --k) std::printf("_n%u##i==--_n%u##i || ",k,k + 1);
std::printf("\\\n i==(");
for (unsigned int k = Nn; k>=2; --k) std::printf("_n%u##i = ",k);
std::printf("--_n1##i); \\\n ");
for (unsigned int k = Np; k>=2; --k) std::printf("_p%u##i = _p%u##i, ",k,k - 1);
if (Np) std::printf("_p1##i = i++, \\\n ");
else std::printf(" ++i, ");
for (unsigned int k = 1; k<Nn; ++k) std::printf("++_n%u##i, ",k);
std::printf("++_n%u##i)\n\n",Nn);
std::printf("#define cimg_for%uX(img,x) cimg_for%u((img)._width,x)\n",N,N);
std::printf("#define cimg_for%uY(img,y) cimg_for%u((img)._height,y)\n",N,N);
std::printf("#define cimg_for%uZ(img,z) cimg_for%u((img)._depth,z)\n",N,N);
std::printf("#define cimg_for%uC(img,c) cimg_for%u((img)._spectrum,c)\n",N,N);
std::printf("#define cimg_for%uXY(img,x,y) cimg_for%uY(img,y) cimg_for%uX(img,x)\n",N,N,N);
std::printf("#define cimg_for%uXZ(img,x,z) cimg_for%uZ(img,z) cimg_for%uX(img,x)\n",N,N,N);
std::printf("#define cimg_for%uXC(img,x,c) cimg_for%uC(img,c) cimg_for%uX(img,x)\n",N,N,N);
std::printf("#define cimg_for%uYZ(img,y,z) cimg_for%uZ(img,z) cimg_for%uY(img,y)\n",N,N,N);
std::printf("#define cimg_for%uYC(img,y,c) cimg_for%uC(img,c) cimg_for%uY(img,y)\n",N,N,N);
std::printf("#define cimg_for%uZC(img,z,c) cimg_for%uC(img,c) cimg_for%uZ(img,z)\n",N,N,N);
std::printf("#define cimg_for%uXYZ(img,x,y,z) cimg_for%uZ(img,z) cimg_for%uXY(img,x,y)\n",N,N,N);
std::printf("#define cimg_for%uXZC(img,x,z,c) cimg_for%uC(img,c) cimg_for%uXZ(img,x,z)\n",N,N,N);
std::printf("#define cimg_for%uYZC(img,y,z,c) cimg_for%uC(img,c) cimg_for%uYZ(img,y,z)\n",N,N,N);
std::printf("#define cimg_for%uXYZC(img,x,y,z,c) cimg_for%uC(img,c) cimg_for%uXYZ(img,x,y,z)\n\n",N,N,N);
}
}
// Generate macro(s) 'cimg_for_inN(i,bound)'
//------------------------------------------
void generate_for_inN(const unsigned int N) {
if (N>=2) {
const unsigned int Nn = N/2, Np = Nn - ((N + 1)%2);
std::printf("#define cimg_for_in%u(bound,i0,i1,i) for (int i = (int)(i0)<0?0:(int)(i0), \\\n",N);
for (unsigned int k = 0; k<Np; ++k)
std::printf(" _p%u##i = i - %u<0?0:i-%u, \\\n",Np - k,Np - k,Np - k);
for (unsigned int k = 1; k<=Nn; ++k)
std::printf(" _n%u##i = i + %u>=(int)(bound)?(int)(bound) - 1:i + %u%c \\\n",k,k,k,k==Nn?';':',');
std::printf(" i<=(int)(i1) && (_n%u##i<(int)(bound) || ",Nn);
for (unsigned int k = Nn - 1; k>=1; --k) std::printf("_n%u##i==--_n%u##i || ",k,k + 1);
std::printf("\\\n i==(");
for (unsigned int k = Nn; k>=2; --k) std::printf("_n%u##i = ",k);
std::printf("--_n1##i)); \\\n ");
for (unsigned int k = Np; k>=2; --k) std::printf("_p%u##i = _p%u##i, ",k,k - 1);
if (Np) std::printf("_p1##i = i++, \\\n ");
else std::printf(" ++i, ");
for (unsigned int k = 1; k<Nn; ++k) std::printf("++_n%u##i, ",k);
std::printf("++_n%u##i)\n\n",Nn);
}
std::printf("#define cimg_for_in%uX(img,x0,x1,x) cimg_for_in%u((img)._width,x0,x1,x)\n",N,N);
std::printf("#define cimg_for_in%uY(img,y0,y1,y) cimg_for_in%u((img)._height,y0,y1,y)\n",N,N);
std::printf("#define cimg_for_in%uZ(img,z0,z1,z) cimg_for_in%u((img)._depth,z0,z1,z)\n",N,N);
std::printf("#define cimg_for_in%uC(img,c0,c1,c) cimg_for_in%u((img)._spectrum,c0,c1,c)\n",N,N);
std::printf("#define cimg_for_in%uXY(img,x0,y0,x1,y1,x,y) cimg_for_in%uY(img,y0,y1,y) "
"cimg_for_in%uX(img,x0,x1,x)\n",N,N,N);
std::printf("#define cimg_for_in%uXZ(img,x0,z0,x1,z1,x,z) cimg_for_in%uZ(img,z0,z1,z) "
"cimg_for_in%uX(img,x0,x1,x)\n",N,N,N);
std::printf("#define cimg_for_in%uXC(img,x0,c0,x1,c1,x,c) cimg_for_in%uC(img,c0,c1,c) "
"cimg_for_in%uX(img,x0,x1,x)\n",N,N,N);
std::printf("#define cimg_for_in%uYZ(img,y0,z0,y1,z1,y,z) cimg_for_in%uZ(img,z0,z1,z) "
"cimg_for_in%uY(img,y0,y1,y)\n",N,N,N);
std::printf("#define cimg_for_in%uYC(img,y0,c0,y1,c1,y,c) cimg_for_in%uC(img,c0,c1,c) "
"cimg_for_in%uY(img,y0,y1,y)\n",N,N,N);
std::printf("#define cimg_for_in%uZC(img,z0,c0,z1,c1,z,c) cimg_for_in%uC(img,c0,c1,c) "
"cimg_for_in%uZ(img,z0,z1,z)\n",N,N,N);
std::printf("#define cimg_for_in%uXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in%uZ(img,z0,z1,z) "
"cimg_for_in%uXY(img,x0,y0,x1,y1,x,y)\n",N,N,N);
std::printf("#define cimg_for_in%uXZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in%uC(img,c0,c1,c) "
"cimg_for_in%uXZ(img,x0,y0,x1,y1,x,z)\n",N,N,N);
std::printf("#define cimg_for_in%uYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in%uC(img,c0,c1,c) "
"cimg_for_in%uYZ(img,y0,z0,y1,z1,y,z)\n",N,N,N);
std::printf("#define cimg_for_in%uXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) cimg_for_in%uC(img,c0,c1,c) "
"cimg_for_in%uXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)\n\n",N,N,N);
}
// Generate macro 'cimg_forMxN[xP](img,x,y,z,c,I,T)'
//--------------------------------------------------
void generate_forMxNxP(const unsigned int M, const unsigned int N, const unsigned int P) {
char indx[16], indy[16], indz[16];
const int
Mn = (int)(M/2), Mp = (int)(Mn - ((M + 1)%2)),
Nn = (int)(N/2), Np = (int)(Nn - ((N + 1)%2)),
Pn = (int)(P/2), Pp = (int)(Pn - ((P + 1)%2)),
last = (int)(M*N*P);
if (P>1) std::printf("#define cimg_for%ux%ux%u(img,x,y,z,c,I,T) \\\n cimg_for%u((img)._depth,z)",M,N,P,P);
else std::printf("#define cimg_for%ux%u(img,x,y,z,c,I,T) \\\n",M,N);
if (N>1) std::printf(" cimg_for%u((img)._height,y) ",N);
else std::printf(" cimg_forY(img,y) ");
std::printf("for (int x = 0%c \\\n",M>1?',':';');
for (int k = Mp; k>=1; --k) std::printf(" _p%u##x = 0%s",k,k==1?", \\\n":",");
for (int k = 1; k<Mn; ++k) std::printf(" _n%u##x = %u>=((img)._width)?(img).width() - 1:%u, \\\n",k,k,k);
if (M>1) {
std::printf(" _n%u##x = (int)( \\\n ",Mn);
for (int k = 0, z = -Pp; z<=Pn; ++z)
for (int y = -Np; y<=Nn; ++y) {
for (int x = -Mp; x<=0; ++x) { std::printf("%sI[%d] =",k && x==-Mp?" (":(x==-Mp?"(":" "),k); ++k; }
k+=Mn;
if (y<0) std::sprintf(indy,"_p%d##",-y); else if (y>0) std::sprintf(indy,"_n%d##",y); else indy[0]='\0';
if (z<0) std::sprintf(indz,"_p%d##",-z); else if (z>0) std::sprintf(indz,"_n%d##",z); else indz[0]='\0';
std::printf(" (T)(img)(0,%sy,%sz,c))%s",indy,indz,k>=last?",":", \\\n");
}
std::printf(" \\\n");
for (int x = 1; x<Mn; ++x)
for (int z = -Pp; z<=Pn; ++z)
for (int y = -Np; y<=Nn; ++y) {
if (y<0) std::sprintf(indy,"_p%d##",-y); else if (y>0) std::sprintf(indy,"_n%d##",y); else indy[0]='\0';
if (z<0) std::sprintf(indz,"_p%d##",-z); else if (z>0) std::sprintf(indz,"_n%d##",z); else indz[0]='\0';
std::printf(" (I[%d] = (T)(img)(_n%d##x,%sy,%sz,c)), \\\n",(Mp + x) + (y + Np)*M + (z + Pp)*M*N,x,indy,indz);
}
std::printf(" %u>=((img)._width)?(img).width() - 1:%u); \\\n",Mn,Mn);
}
if (M>1) std::printf(" (_n%u##x",Mn); else std::printf(" (x");
std::printf("<(img).width() && ( \\\n");
for (int z = -Pp; z<=Pn; ++z)
for (int y = -Np; y<=Nn; ++y) {
if (M>1) std::sprintf(indx,"_n%d##",Mn); else indx[0]='\0';
if (y<0) std::sprintf(indy,"_p%d##",-y); else if (y>0) std::sprintf(indy,"_n%d##",y); else indy[0]='\0';
if (z<0) std::sprintf(indz,"_p%d##",-z); else if (z>0) std::sprintf(indz,"_n%d##",z); else indz[0]='\0';
std::printf(" (I[%d] = (T)(img)(%sx,%sy,%sz,c))%s",M - 1 + (y + Np)*M + (z + Pp)*M*N,indx,indy,indz,
z==Pn && y==Nn?",1))":", \\\n");
}
if (M>1) {
std::printf(" || \\\n ");
for (int k = Mn - 1; k>=1; --k) std::printf("_n%d##x==--_n%u##x || ",k,k + 1);
std::printf("x==(");
for (int k = Mn; k>=2; --k) std::printf("_n%d##x = ",k);
std::printf("--_n1##x); \\\n");
} else std::printf("; \\\n");
if (M>1) {
for (unsigned int k = 0, z = 0; z<P; ++z)
for (unsigned int y = 0; y<N; ++y) {
for (unsigned int x = 0; x<M - 1; ++x) {
std::printf(" I[%d] = I[%d],",k,k + 1);
++k;
}
std::printf(" \\\n");
++k;
}
std::printf(" ");
for (int k = Mp; k>=2; --k) std::printf("_p%d##x = _p%d##x, ",k,k - 1);
if (M>2) std::printf("_p1##x = x++, "); else std::printf("++x, ");
for (int k = 1; k<=Mn - 1; ++k) std::printf("++_n%d##x, ",k);
std::printf("++_n%d##x)\n\n",Mn);
} else std::printf(" ++x)\n\n");
}
// Generate macro 'cimg_for_inMxN[xP](img,x,y,z,c,I,T)'
//-----------------------------------------------------
void generate_for_inMxNxP(const unsigned int M, const unsigned int N, const unsigned int P) {
char indx[16], indy[16], indz[16];
const int
Mn = (int)(M/2), Mp = (int)(Mn - ((M + 1)%2)),
Nn = (int)(N/2), Np = (int)(Nn - ((N + 1)%2)),
Pn = (int)(P/2), Pp = (int)(Pn - ((P + 1)%2));
if (P>1)
std::printf("#define cimg_for_in%ux%ux%u(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \\\n "
"cimg_for_in%u((img)._depth,z0,z1,z)",M,N,P,P);
else std::printf("#define cimg_for_in%ux%u(img,x0,y0,x1,y1,x,y,z,c,I,T) \\\n",M,N);
if (N>1) std::printf(" cimg_for_in%u((img)._height,y0,y1,y) ",N);
else std::printf(" cimg_for_inY(img,y0,y1,y) ");
std::printf("for (int x = (int)(x0)<0?0:(int)(x0)%c \\\n",M>1?',':';');
for (int k = Mp; k>=1; --k) std::printf(" _p%u##x = x - %u<0?0:x - %u, \\\n",k,k,k);
for (int k = 1; k<Mn; ++k) std::printf(" _n%u##x = x + %u>=(img).width()?(img).width() - 1:x + %u, \\\n",k,k,k);
if (M>1) {
std::printf(" _n%u##x = (int)( \\\n",Mn);
for (int x = -Mp; x<Mn; ++x)
for (int z = -Pp; z<=Pn; ++z)
for (int y = -Np; y<=Nn; ++y) {
if (x<0) std::sprintf(indx,"_p%d##",-x); else if (x>0) std::sprintf(indx,"_n%d##",x); else indx[0]='\0';
if (y<0) std::sprintf(indy,"_p%d##",-y); else if (y>0) std::sprintf(indy,"_n%d##",y); else indy[0]='\0';
if (z<0) std::sprintf(indz,"_p%d##",-z); else if (z>0) std::sprintf(indz,"_n%d##",z); else indz[0]='\0';
std::printf(" (I[%d] = (T)(img)(%sx,%sy,%sz,c)), \\\n",(Mp + x) + (y + Np)*M + (z + Pp)*M*N,indx,indy,indz);
}
std::printf(" x + %u>=(img).width()?(img).width() - 1:x + %u); \\\n",Mn,Mn);
}
std::printf(" x<=(int)(x1) && (");
if (M>1) std::printf("(_n%u##x",Mn); else std::printf("(x");
std::printf("<(img).width() && ( \\\n");
for (int z = -Pp; z<=Pn; ++z)
for (int y = -Np; y<=Nn; ++y) {
if (M>1) std::sprintf(indx,"_n%d##",Mn); else indx[0]='\0';
if (y<0) std::sprintf(indy,"_p%d##",-y); else if (y>0) std::sprintf(indy,"_n%d##",y); else indy[0]='\0';
if (z<0) std::sprintf(indz,"_p%d##",-z); else if (z>0) std::sprintf(indz,"_n%d##",z); else indz[0]='\0';
std::printf(" (I[%d] = (T)(img)(%sx,%sy,%sz,c))%s",M - 1 + (y + Np)*M + (z + Pp)*M*N,indx,indy,indz,
z==Pn && y==Nn?",1))":", \\\n");
}
if (M>1) {
std::printf(" || \\\n ");
for (int k = Mn - 1; k>=1; --k) std::printf("_n%d##x==--_n%u##x || ",k,k + 1);
std::printf("x==(");
for (int k = Mn; k>=2; --k) std::printf("_n%d##x = ",k);
std::printf("--_n1##x)); \\\n");
} else std::printf("); \\\n");
if (M>1) {
for (unsigned int k = 0, z = 0; z<P; ++z)
for (unsigned int y = 0; y<N; ++y) {
for (unsigned int x = 0; x<M - 1; ++x) {
std::printf(" I[%d] = I[%d],",k,k + 1);
++k;
}
std::printf(" \\\n");
++k;
}
std::printf(" ");
for (int k = Mp; k>=2; --k) std::printf("_p%d##x = _p%d##x, ",k,k - 1);
if (M>2) std::printf("_p1##x = x++, "); else std::printf("++x, ");
for (int k = 1; k<=Mn - 1; ++k) std::printf("++_n%d##x, ",k);
std::printf("++_n%d##x)\n\n",Mn);
} else std::printf(" ++x)\n\n");
}
// Generate macro 'cimg_getMxN[xP](img,x,y,z,c,I,T)'
//--------------------------------------------------
void generate_getMxNxP(const unsigned int M, const unsigned int N, const unsigned int P) {
const int
Mn = (int)(M/2), Mp = (int)(Mn - ((M + 1)%2)),
Nn = (int)(N/2), Np = (int)(Nn - ((N + 1)%2)),
Pn = (int)(P/2), Pp = (int)(Pn - ((P + 1)%2)),
last = M*N*P - 1;
if (P>1) std::printf("#define cimg_get%ux%ux%u(img,x,y,z,c,I,T) \\\n",M,N,P);
else std::printf("#define cimg_get%ux%u(img,x,y,z,c,I,T) \\\n",M,N);
char indx[16], indy[16], indz[16];
for (int k = 0, z = -Pp; z<=Pn; ++z)
for (int y = -Np; y<=Nn; ++y)
for (int x = -Mp; x<=Mn; ++x) {
if (x<0) std::sprintf(indx,"_p%d##",-x); else if (x>0) std::sprintf(indx,"_n%d##",x); else indx[0]='\0';
if (y<0) std::sprintf(indy,"_p%d##",-y); else if (y>0) std::sprintf(indy,"_n%d##",y); else indy[0]='\0';
if (z<0) std::sprintf(indz,"_p%d##",-z); else if (z>0) std::sprintf(indz,"_n%d##",z); else indz[0]='\0';
std::printf(" I[%u] = (T)(img)(%sx,%sy,%sz,c)%s",k,indx,indy,indz,
k==last?";\n\n":(x==Mn?", \\\n":","));
++k;
}
}
//-----------------
// Main Procedure
//-----------------
int main(int argc, char **argv) {
cimg_usage("Generate C++ macros to deal with MxN[xP] neighborhood loops within the CImg Library");
// Read command line arguments
//----------------------------
const char *const size = cimg_option("-s","5x4","Size of the neighborhood");
const bool do_forN = cimg_option("-forN",true,"Generate 'cimg_forN()'");
const bool do_for_inN = cimg_option("-for_inN",true,"Generate 'cimg_for_inN()'");
const bool do_for = cimg_option("-for",true,"Generate 'cimg_forMxNxP()'");
const bool do_for_in = cimg_option("-for_in",true,"Generate 'cimg_for_inMxNxP()'");
const bool do_get = cimg_option("-get",true,"Generate 'cimg_getMxNxP()'");
if (cimg_option("-h",false,0)) std::exit(0);
unsigned int M = 1, N = 1 , P = 1;
std::sscanf(size,"%u%*c%u%*c%u",&M,&N,&P);
if (!M || !N || !P || (M==1 && N==1 && P==1)) {
std::fprintf(stderr,"\n%s : Error, bad neighborhood size '%s'\n",argv[0],size);
std::exit(0);
}
if (!do_forN && !do_get && !do_for) return 0;
if (P>1)
std::printf("// Define %ux%ux%u loop macros\n"
"//----------------------------\n",M,N,P);
else
std::printf("// Define %ux%u loop macros\n"
"//-------------------------\n",M,N);
if (do_forN) {
if (N>1) generate_forN(N);
if (P>1 && P!=N) generate_forN(P);
}
if (do_for_inN) {
if (N>1) generate_for_inN(N);
if (P>1 && P!=N) generate_for_inN(P);
}
if (do_for) generate_forMxNxP(M,N,P);
if (do_for_in) generate_for_inMxNxP(M,N,P);
if (do_get) generate_getMxNxP(M,N,P);
return 0;
}

View file

@ -0,0 +1,146 @@
/*
#
# File : hough_transform2d.cpp
# ( C++ source file )
#
# Description : Implementation of the Hough transform.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main(int argc,char **argv) {
cimg_usage("Illustration of the Hough transform");
CImg<unsigned char> src(cimg_option("-i",cimg_imagepath "parrot.ppm","Input image"));
CImg<> vote(500,400,1,1,0), img = src.get_norm().normalize(0,255).resize(-100,-100,1,2,2);
CImgDisplay disp(src,"Image"), dispvote(vote,"Hough Transform");
const unsigned char col1[3]={255,255,255}, col2[3]={0,0,0};
const double
alpha = cimg_option("-a",1.5,"Gradient smoothing"),
sigma = cimg_option("-s",0.5,"Hough Transform smoothing"),
rhomax = std::sqrt((double)(img.width()*img.width() + img.height()*img.height()))/2,
thetamax = 2*cimg::PI;
if (cimg::dialog(cimg::basename(argv[0]),
"Instructions : \n"
"----------------\n\n"
"(1) When clicking on the color image, all lines crossing the selected point\n"
"will be voted in the Hough buffer.\n\n"
"(2) When clicking on the Hough buffer, the corresponding line is drawn\n"
"on the color image.\n\n"
"(3) When pressing the space bar, lines in the color image are detected from the\n"
"image gradients through votes in the Hough buffer.\n\n"
"Note that a logarithmic scaling is performed for displayin the vote image.\n"
"See also the available options (option '-h')\n","Start !","Quit",0,0,0,0,
src.get_resize(100,100,1,3),true)) std::exit(0);
while (!disp.is_closed() && !dispvote.is_closed() &&
!disp.is_keyQ() && !dispvote.is_keyQ() && !disp.is_keyESC() && !dispvote.is_keyESC()) {
CImgDisplay::wait(disp,dispvote);
// When pressing space bar, the vote is performed from the image gradients.
if (dispvote.is_keySPACE() || disp.is_keySPACE()) {
CImgList<> grad = img.get_gradient();
cimglist_for(grad,l) grad[l].blur((float)alpha);
vote.fill(0);
cimg_forXY(img,x,y) {
const double
X = (double)x - img.width()/2,
Y = (double)y - img.height()/2,
gx = grad[0](x,y),
gy = grad[1](x,y);
double
theta = std::atan2(gy,gx),
rho = std::sqrt(X*X + Y*Y)*std::cos(std::atan2(Y,X) - theta);
if (rho<0) { rho=-rho; theta+=cimg::PI; }
theta = cimg::mod(theta,thetamax);
vote((int)(theta*dispvote.width()/thetamax),(int)(rho*dispvote.height()/rhomax))+=
(float)std::sqrt(gx*gx + gy*gy);
}
vote.blur((float)sigma);
CImg<> vote2(vote); cimg_forXY(vote2,x,y) vote2(x,y) = (float)std::log(1 + vote(x,y)); vote2.display(dispvote);
}
// When clicking on the vote window.
if (dispvote.button()) {
const double
rho = dispvote.mouse_y()*rhomax/dispvote.height(),
theta = dispvote.mouse_x()*thetamax/dispvote.width(),
x = img.width()/2 + rho*std::cos(theta),
y = img.height()/2 + rho*std::sin(theta);
const int
x0 = (int)(x + 1000*std::sin(theta)),
y0 = (int)(y - 1000*std::cos(theta)),
x1 = (int)(x - 1000*std::sin(theta)),
y1 = (int)(y + 1000*std::cos(theta));
CImg<unsigned char>(src).
draw_line(x0,y0,x1,y1,col1,1.0f,0xF0F0F0F0).draw_line(x0,y0,x1,y1,col2,1.0f,0x0F0F0F0F).
draw_line(x0 + 1,y0,x1 + 1,y1,col1,1.0f,0xF0F0F0F0).draw_line(x0 + 1,y0,x1 + 1,y1,col2,1.0f,0x0F0F0F0F).
draw_line(x0,y0 + 1,x1,y1 + 1,col1,1.0f,0xF0F0F0F0).draw_line(x0,y0 + 1,x1,y1 + 1,col2,1.0f,0x0F0F0F0F).
display(disp);
}
// When clicking on the image.
if (disp.button() && disp.mouse_x()>=0) {
const double
x0 = (double)disp.mouse_x() - disp.width()/2,
y0 = (double)disp.mouse_y() - disp.height()/2,
rho0 = std::sqrt(x0*x0 + y0*y0),
theta0 = std::atan2(y0,x0);
for (double t=0; t<thetamax; t+=0.001) {
double theta = t, rho = rho0*std::cos(theta0 - t);
if (rho<0) { rho=-rho; theta=cimg::mod(theta + cimg::PI,thetamax); }
vote((int)(theta*vote.width()/thetamax),(int)(rho*vote.height()/rhomax))+=1;
}
CImg<> vote2(vote); cimg_forXY(vote2,x,y) vote2(x,y) = (float)std::log(1 + vote(x,y)); vote2.display(dispvote);
}
dispvote.resize(dispvote);
disp.resize(disp);
}
std::exit(0);
return 0;
}

157
examples/image2ascii.cpp Normal file
View file

@ -0,0 +1,157 @@
/*
#
# File : image2ascii.cpp
# ( C++ source file )
#
# Description : A basic image to ASCII-art converter.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
// Tell CImg not to use display capabilities.
#undef cimg_display
#define cimg_display 0
#include "CImg.h"
using namespace cimg_library;
/*---------------------------
Main procedure
--------------------------*/
int main(int argc,char **argv) {
cimg_usage("A simple image to ASCII-art converter.\n\nUsage : image2ascii [options] image");
// Read command line parameters
const char *const file_i = cimg_option("-i",(char*)0,"Input image");
const char *const geom = cimg_option("-g","79x40","Output size");
const int alphabet = cimg_option("-a",0,"Alphabet type (0=full, 1=numbers, 2=letters, 3=signs, 4=minimal");
const bool invert = cimg_option("-invert",false,"Invert image intensities");
const float contour = (float)cimg_option("-contour",0.0f,"Use image contours higher than specified threshold");
const float blur = (float)cimg_option("-blur",0.8f,"Image pre-blur");
const float sigma = (float)cimg_option("-sigma",10.0f,"Font pre-blur");
int w = 79, h = 40;
std::sscanf(geom,"%d%*c%d",&w,&h);
if (cimg_option("-h",false,0)) std::exit(0);
// Init fonts
CImgList<> font_full = CImgList<>::font(13,false);
font_full.remove(0,255);
const int fw = font_full[(int)'A'].width(), fh = font_full[(int)'A'].height();
CImgList<> font, font_blur;
CImgList<unsigned char> font_code;
switch (alphabet) {
case 1: {
font_code.insert(CImg<>::vector(' '));
for (unsigned char l='0'; l<='9'; l++) font_code.insert(CImg<>::vector(l));
} break;
case 2: {
font_code.insert(CImg<>::vector(' '));
for (unsigned char l='A'; l<='Z'; l++) font_code.insert(CImg<>::vector(l));
} break;
case 3: {
font_code.insert(CImg<>::vector(' '));
font_code.insert(CImg<>::vector('-'));
font_code.insert(CImg<>::vector('_'));
font_code.insert(CImg<>::vector('|'));
font_code.insert(CImg<>::vector('/'));
font_code.insert(CImg<>::vector('\\'));
font_code.insert(CImg<>::vector('+'));
font_code.insert(CImg<>::vector('.'));
font_code.insert(CImg<>::vector('*'));
font_code.insert(CImg<>::vector('='));
font_code.insert(CImg<>::vector(']'));
font_code.insert(CImg<>::vector('['));
font_code.insert(CImg<>::vector('('));
font_code.insert(CImg<>::vector(')'));
font_code.insert(CImg<>::vector('{'));
font_code.insert(CImg<>::vector('}'));
font_code.insert(CImg<>::vector('"'));
font_code.insert(CImg<>::vector('!'));
font_code.insert(CImg<>::vector('$'));
} break;
case 4: {
font_code.insert(CImg<>::vector(' '));
font_code.insert(CImg<>::vector('.'));
font_code.insert(CImg<>::vector('/'));
font_code.insert(CImg<>::vector('\\'));
font_code.insert(CImg<>::vector('_'));
font_code.insert(CImg<>::vector('_'));
font_code.insert(CImg<>::vector('|'));
} break;
default: { for (unsigned char l=' '; l<='~'; l++) font_code.insert(CImg<>::vector(l)); } break;
}
cimglist_for(font_code,l) {
font.insert(font_full(font_code[l](0)));
font_blur.insert(font[l].get_resize(fw,fh,1,1).blur(sigma).normalize(0,255));
}
// Init images
CImg<> img;
if (!file_i) { float white[3] = { 255,255,255 }; img.assign().draw_text(0,0," CImg\nRocks !",white); }
else img.assign(file_i);
img.norm().resize(fw*w,fh*h);
if (blur) img.blur(blur);
if (contour>0) {
CImgList<> grad = img.get_gradient("xy",4);
img = (grad[0].pow(2) + grad[1].pow(2)).sqrt().normalize(0,100).threshold(contour);
}
img.normalize(0,255);
if (invert) img = 255.0f - img;
CImg<unsigned char> dest(w,h,1,1,0);
// Render ASCII-art image, using a simple correlation method.
CImg<> neigh;
cimg_forY(dest,y) { cimg_forX(dest,x) {
neigh = img.get_crop(x*fw,y*fh,(x + 1)*fw,(y + 1)*fh);
float scoremin = 2e28f;
unsigned int best = 0;
cimglist_for(font_code,l) {
const CImg<>& letter = font_blur[l];
const float score = (float)((letter - neigh).pow(2).sum());
if (score<scoremin) { scoremin = score; best = l; }
}
dest(x,y) = (unsigned char)best;
std::fprintf(stdout,"%c",font_code[dest(x,y)](0));
}
std::fprintf(stdout,"\n");
}
std::exit(0);
return 0;
}

View file

@ -0,0 +1,216 @@
/*
#
# File : image_registration2d.cpp
# ( C++ source file )
#
# Description : Compute a motion field between two images,
# with a multiscale and variational algorithm.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
#undef min
#undef max
// animate_warp() : Create warping animation from two images and a motion field
//----------------
void animate_warp(const CImg<unsigned char>& src, const CImg<unsigned char>& dest, const CImg<>& U,
const bool morph, const bool imode, const char *filename,int nb, CImgDisplay& disp) {
CImg<unsigned char> visu = (src,dest,src)>'x', warp(src);
float t = 0;
for (unsigned int iteration = 0; !disp || (!disp.is_closed() && !disp.is_keyQ()); ++iteration) {
if (morph) cimg_forXYC(warp,x,y,k) {
const float dx = U(x,y,0), dy = U(x,y,1),
I1 = (float)src.linear_atXY(x - t*dx, y - t*dy, k),
I2 = (float)dest.linear_atXY(x + (1 - t)*dx,y + (1 - t)*dy,k);
warp(x,y,k) = (unsigned char)((1 - t)*I1 + t*I2);
} else cimg_forXYC(warp,x,y,k) {
const float dx = U(x,y,0), dy = U(x,y,1), I1 = (float)src.linear_atXY(x - t*dx, y - t*dy, 0,k);
warp(x,y,k) = (unsigned char)I1;
}
if (disp) visu.draw_image(2*src.width(),warp).display(disp.resize().wait(30));
if (filename && *filename && (imode || (int)iteration<nb)) {
std::fprintf(stderr,"\r > frame %d ",iteration);
warp.save(filename,iteration);
}
t+=1.0f/nb;
if (t<0) { t = 0; nb = -nb; }
if (t>1) { t = 1; nb = -nb; if (filename && *filename) std::exit(0); }
}
}
// optflow() : multiscale version of the image registration algorithm
//-----------
CImg<> optflow(const CImg<>& source, const CImg<>& target,
const float smoothness, const float precision, const unsigned int nb_scales, CImgDisplay& disp) {
const unsigned int iteration_max = 100000;
const float _precision = (float)std::pow(10.0,-(double)precision);
const CImg<>
src = source.get_resize(target,3).normalize(0,1),
dest = target.get_normalize(0,1);
CImg<> U;
const unsigned int _nb_scales = nb_scales>0?nb_scales:
(unsigned int)(2*std::log((double)(std::max(src.width(),src.height()))));
for (int scale = _nb_scales - 1; scale>=0; --scale) {
const float factor = (float)std::pow(1.5,(double)scale);
const unsigned int
_sw = (unsigned int)(src.width()/factor), sw = _sw?_sw:1,
_sh = (unsigned int)(src.height()/factor), sh = _sh?_sh:1;
const CImg<>
I1 = src.get_resize(sw,sh,1,-100,2),
I2 = dest.get_resize(I1,2);
std::fprintf(stderr," * Scale %d\n",scale);
if (U) (U*=1.5f).resize(I2.width(),I2.height(),1,-100,3);
else U.assign(I2.width(),I2.height(),1,2,0);
float dt = 2, energy = cimg::type<float>::max();
const CImgList<> dI = I2.get_gradient();
for (unsigned int iteration = 0; iteration<iteration_max; ++iteration) {
std::fprintf(stderr,"\r- Iteration %d - E = %g",iteration,energy); std::fflush(stderr);
float _energy = 0;
cimg_for3XY(U,x,y) {
const float
X = x + U(x,y,0),
Y = y + U(x,y,1);
float deltaI = 0;
cimg_forC(I2,c) deltaI+=(float)(I1(x,y,c) - I2.linear_atXY(X,Y,c));
float _energy_regul = 0;
cimg_forC(U,c) {
const float
Ux = 0.5f*(U(_n1x,y,c) - U(_p1x,y,c)),
Uy = 0.5f*(U(x,_n1y,c) - U(x,_p1y,c)),
Uxx = U(_n1x,y,c) + U(_p1x,y,c),
Uyy = U(x,_n1y,c) + U(x,_p1y,c);
U(x,y,c) = (float)( U(x,y,c) + dt*(deltaI*dI[c].linear_atXY(X,Y) +
smoothness* ( Uxx + Uyy )))/(1 + 4*smoothness*dt);
_energy_regul+=Ux*Ux + Uy*Uy;
}
_energy+=deltaI*deltaI + smoothness*_energy_regul;
}
const float d_energy = (_energy - energy)/(sw*sh);
if (d_energy<=0 && -d_energy<_precision) break;
if (d_energy>0) dt*=0.5f;
energy = _energy;
if (disp) disp.resize();
if (disp && disp.is_closed()) std::exit(0);
if (disp && !(iteration%300)) {
const unsigned char white[] = { 255,255,255 };
CImg<unsigned char> tmp = I1.get_warp(U,true,true,1).normalize(0,200);
tmp.resize(disp.width(),disp.height()).draw_quiver(U,white,0.7f,15,-14,true).display(disp);
}
}
std::fprintf(stderr,"\n");
}
return U;
}
/*------------------------
Main function
------------------------*/
int main(int argc,char **argv) {
// Read command line parameters
cimg_usage("Compute an optical flow between two 2D images, and create a warped animation");
const char
*name_i1 = cimg_option("-i",cimg_imagepath "sh0r.pgm","Input Image 1 (Destination)"),
*name_i2 = cimg_option("-i2",cimg_imagepath "sh1r.pgm","Input Image 2 (Source)"),
*name_o = cimg_option("-o",(const char*)NULL,"Output 2D flow (inrimage)"),
*name_seq = cimg_option("-o2",(const char*)NULL,"Output Warping Sequence");
const float
smoothness = cimg_option("-s",0.1f,"Flow Smoothness"),
precision = cimg_option("-p",6.0f,"Convergence precision");
const unsigned int
nb = cimg_option("-n",40,"Number of warped frames"),
nb_scales = cimg_option("-scale",0,"Number of scales (0=auto)");
const bool
normalize = cimg_option("-equalize",true,"Histogram normalization of the images"),
morph = cimg_option("-m",true,"Morphing mode"),
imode = cimg_option("-c",true,"Complete interpolation (or last frame is missing)"),
dispflag = !cimg_option("-novisu",false,"Visualization");
// Init images and display
std::fprintf(stderr," - Init images.\n");
const CImg<>
src(name_i1),
dest(CImg<>(name_i2).resize(src,3)),
src_blur = normalize?src.get_blur(0.5f).equalize(256):src.get_blur(0.5f),
dest_blur = normalize?dest.get_blur(0.5f).equalize(256):dest.get_blur(0.5f);
CImgDisplay disp;
if (dispflag) {
unsigned int w = src.width(), h = src.height();
const unsigned int dmin = std::min(w,h), minsiz = 512;
if (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; }
const unsigned int dmax = std::max(w,h), maxsiz = 1024;
if (dmax>maxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; }
disp.assign(w,h,"Estimated Motion",0);
}
// Run Motion estimation algorithm
std::fprintf(stderr," - Compute optical flow.\n");
const CImg<> U = optflow(src_blur,dest_blur,smoothness,precision,nb_scales,disp);
if (name_o) U.save(name_o);
U.print("Computed flow");
// Do morphing animation
std::fprintf(stderr," - Create warped animation.\n");
CImgDisplay disp2;
if (dispflag) {
unsigned int w = src.width(), h = src.height();
const unsigned int dmin = std::min(w,h), minsiz = 100;
if (dmin<minsiz) { w = w*minsiz/dmin; h=h*minsiz/dmin; }
const unsigned int dmax = std::max(w,h), maxsiz = 1024/3;
if (dmax>maxsiz) { w = w*maxsiz/dmax; h=h*maxsiz/dmax; }
disp2.assign(3*w,h,"Source/Destination images and Motion animation",0);
}
animate_warp(src.get_normalize(0,255),dest.get_normalize(0,255),U,morph,imode,name_seq,nb,disp2);
std::exit(0);
return 0;
}

View file

@ -0,0 +1,140 @@
/*
#
# File : image_surface3d.cpp
# ( C++ source file )
#
# Description : This tool allows to show an image as a 3D surface.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line arguments.
cimg_usage("Render an image as a surface");
const char *file_i = cimg_option("-i",cimg_imagepath "logo.bmp","Input image");
const char *file_o = cimg_option("-o",(char*)0,"Output 3D object");
const float sigma = cimg_option("-smooth",1.0f,"Amount of image smoothing");
const float ratioz = cimg_option("-z",0.25f,"Aspect ratio along z-axis");
const unsigned int di = cimg_option("-di",10,"Step for isophote skipping");
// Load 2D image file.
std::fprintf(stderr,"\n- Load file '%s'",cimg::basename(file_i)); std::fflush(stderr);
const CImg<unsigned char>
img = CImg<>(file_i).blur(sigma).resize(-100,-100,1,3),
norm = img.get_norm().normalize(0,255);
// Compute surface with triangles.
std::fprintf(stderr,"\n- Create image surface"); std::fflush(stderr);
CImgList<unsigned int> primitives;
CImgList<unsigned char> colors;
const CImg<> points = img.get_elevation3d(primitives,colors,norm*-ratioz);
// Compute image isophotes.
std::fprintf(stderr,"\n- Compute image isophotes"); std::fflush(stderr);
CImgList<unsigned int> isoprimitives;
CImgList<unsigned char> isocolors;
CImg<> isopoints;
for (unsigned int i = 0; i<255; i+=di) {
CImgList<> prims;
const CImg<> pts = norm.get_isoline3d(prims,(float)i);
isopoints.append_object3d(isoprimitives,pts,prims);
}
cimglist_for(isoprimitives,l) {
const unsigned int i0 = isoprimitives(l,0);
const float x0 = isopoints(i0,0), y0 = isopoints(i0,1);
const unsigned char
r = (unsigned char)img.linear_atXY(x0,y0,0),
g = (unsigned char)img.linear_atXY(x0,y0,1),
b = (unsigned char)img.linear_atXY(x0,y0,2);
isocolors.insert(CImg<unsigned char>::vector(r,g,b));
}
cimg_forX(isopoints,ll) isopoints(ll,2) = -ratioz*norm.linear_atXY(isopoints(ll,0),isopoints(ll,1));
// Save object if necessary
if (file_o) {
std::fprintf(stderr,"\n- Save 3d object as '%s'",cimg::basename(file_o)); std::fflush(stderr);
points.save_off(primitives,colors,file_o);
}
// Enter event loop
std::fprintf(stderr,
"\n- Enter interactive loop.\n\n"
"Reminder : \n"
" + Use mouse to rotate and zoom object\n"
" + key 'F' : Toggle fullscreen\n"
" + key 'Q' or 'ESC' : Quit\n"
" + Any other key : Change rendering type\n\n"); std::fflush(stderr);
const char *const title = "Image viewed as a surface";
CImgDisplay disp(800,600,title,0);
unsigned int rtype = 2;
CImg<float> pose = CImg<float>::identity_matrix(4);
while (!disp.is_closed()) {
const unsigned char white[3]={ 255, 255, 255 };
CImg<unsigned char> visu(disp.width(),disp.height(),1,3,0);
visu.draw_text(10,10,"%s",white,0,1,24,
rtype==0?"Points":(rtype==1?"Lines":(rtype==2?"Faces":(rtype==3?"Flat-shaded faces":
(rtype==4?"Gouraud-shaded faces":(rtype==5?"Phong-shaded faces":"Isophotes"))))));
static bool first_time = true;
if (rtype==6) visu.display_object3d(disp,isopoints,isoprimitives,isocolors,first_time,1,-1,true,
500.0f,0.0f,0.0f,-5000.0f,0.0f,0.0f,true,pose.data());
else visu.display_object3d(disp,points,primitives,colors,first_time,rtype,-1,true,
500.0f,0.0f,0.0f,-5000.0f,0.0f,0.0f,true,pose.data());
first_time = false;
switch (disp.key()) {
case 0: break;
case cimg::keyBACKSPACE: rtype = (7 + rtype - 1)%7; break;
case cimg::keyQ:
case cimg::keyESC: disp.close(); break;
case cimg::keyF:
if (disp.is_fullscreen()) disp.resize(800,600); else disp.resize(disp.screen_width(),disp.screen_height());
disp.toggle_fullscreen();
break;
default: rtype = (rtype + 1)%7; break;
}
}
return 0;
}

27810
examples/img/CImg_demo.h Normal file

File diff suppressed because it is too large Load diff

BIN
examples/img/logo.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
examples/img/milla.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

79162
examples/img/odykill.h Normal file

File diff suppressed because it is too large Load diff

BIN
examples/img/parrot.ppm Normal file

Binary file not shown.

Binary file not shown.

256
examples/img/sh0r.pgm Normal file
View file

@ -0,0 +1,256 @@
P5
# CREATOR: CImg : Original size=180x180x1x1
180 180
255
窘拷揪揪烤烤靠靠靠靠靠究究澜纠窘两铰济宦纠纠两览两揽览嚼祭伎究靠靠靠郊换汉垢贩贩犯够骄窘己狗抖抖斗贩父阜付范范贩贩父垢汗还缓还换换换浇杭亢涣菇炯豢换拷患窘伎季浇拷窘窘炯郊冀己竞交技嚼祭娇究究究究靠纠靠烤靠谰祭阑柯姑凉殴藕戮辆铰量慌靠炕霉霉两究靠坷揽交付兜创闯膊扯购技窘己阜兜刀斗犯父父犯蹈蹈倒倒逗坊坊富讣讣购换蓟航郊读看没航碌辆妇究患亢兰窘娇伎伎伎痪蓟焕防妇患烤烤揪烤烤烤烤靠烤靠谰拷坷纠宦炯暮矫涣靠纠究驴娇偶铰寄鼓毫骄揪靠坷谰欢背富钩<EFBFBD><EFBFBD>櫅灐Μ掣汗洞吵吹斗腹垢父范返复傅沟狗构汗汗桓几缓缓换靖豢拷孤咕烤镀犊亢炕揪焕豪涣豢炯炕炕炕炯靖练拦净考澜烤烤靠究嚼究纠靠纠嚼窘潞暮览毫禄辆铰究苛究磕孤禄姆藕澜揪揪究靠胶副┄ⅱう<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>泊捣腹构垢范抖刀捣斗犯构购汉夯够夯杭换蓟扛礁粱烤辜么鸥烤豢郊拦赂母禄究涣毫豪壕嚎噶妨附搅涣嚼娇究拷澜谰烤烤拷澜坷荒改冀晾孤玖骄揽澜澜霉沤韭浩豪揪揪揪揪揪沟副┉<EFBFBD>枎妸妺敜┃ΗぇЁ┈<EFBFBD>捣构腹阜兜档档抖贩父构构汉汗汉汉缓换航孤杜独焦陆钙茨估郊究郝放杜估郊凉鹿梁考交抗练梁阑潞粱澜揽纠嚼究靠靠究纠究梁墓览交每毫谰辆韭侥郝搅拷禄谰揪揪浇蓟患狗矝倄kc]]aipv}墠寪殺灆洖·ǐ<C2B7>刀潮车档创吹档抖贩父构构构购汉汉换患痪该的杭霉矫彩称咐窘嚼郝改孤伎考粱阑拷伎唤竞篮窘潞潞禄澜靠嚼究靠靠靠究究娇阑两伎良济冀禄晾寄宦靠两澜谰揪究郊己覆<E5B7B1>杸_C8=96:AIS^ckt||z€唹崟潱Ι<E6BDB1><CE99>Н吵膊吵吹刀斗贩构阜饭汉购汉夯换蓟竞粮揽箍练拾瞬乒究骄考粱录谰嚼嚼娇浇拦鹿拷浇嚼宦宦涣嚼揪澜靠靠靠靠靠究拷靠炯陆毫烤搅济季两辆久沽靠靠究靠汗浇顶塳N5(&*52/036<HT`hkhhqyyy}崪イà晱槯捶床辈吵车抖抖贩返捶汗构构汉换技浇祭唤两浩呈采睹窘澜烤纠嚼究澜澜澜靠幻纺沽嚎冀良兰良澜靠祭究靠靠烤烤究嚼娇娇冀煤两澜烤坷拷揽粱驴靠靠靠烤附罋qUC3+-4<CFEB>;744:FY`YRT^kupz尃<7A>殈kpz€帰<E282AC><E5B8B0><EFBFBD><EFBFBD>渤嘲垂纠冬备阜犯构汉换冀骄娇考苛蛊非杜痪粱禄谰靠靠谰两录两纠蛊杜访壕骄烤窘粱谰纠娇靠靠烤靠玖耗孤伎拷篮澜究嚼嚼娇揽靠靠靠靠靠考郊磶TM>720--/15789::999=HRRNKMVisz}崡峺\R`ry|嚑ǐィⅲぇ<E285B2>煕オ鲍<E382AA><EFBFBD>陡腹购患浇揪烤两苛悸幻娇兰煤没辆揽揽辆两两谰铰鼓改沽嚼伎嚼炯粱揽嚼究靠靠烤玖耗盖访涣季谰嚼涣涣祭嚼搅嚼靠靠靠窘孤膹WNT<2*$!"%),03689:;<<>ABA@>>BUkr€哣7--1569Di儥槗悗憳潚ziccagy敚ⅲ<E6959A>刀刀腹患骄靠靠辆揽靠靠谰良录戮量晾量量揽揽览搅剂剂娇揪悸壕澜靠嚼娇揪烤烤靠幻豢古嚎剂季嚼宦郝涣涣宦剂究靠靠郊捞橇S"Z8%$$%&'*,0479:;;<==;:75540)1H^k`%&,.,***,<b寲湝<E5AFB2>z{oeegjcSPg姎灒┅ДΛ钡够娇坷览量量揽靠靠谰揽览览亮亮晾晾揽坷靠靠靠拷纠沽娇伎娇骄烤烤烤靠济嚎揽估窘骄娇郝该姑孤好郝娇靠靠净够号t"-. %)-1369<>?=<;::9741/.-+()1>>2#($=r崢梽z|xb`^[TONIKaw€垟潰いЛ捕辜纠懒亮亮晾揽靠靠靠坷亮亮亮亮亮亮览揽靠靠靠娇涣焕涣豪娇考靠揪究悸姑豢悸技兰拷祭孤孤孤孤毫伎靠靠拷复炊c+&#*057:;=??=:6310/+)&%$#!# #((Abg[SXTJBIPPKFEFFJT[`k亼洝お安锤娇亮亮亮亮览靠靠靠懒亮侣侣铝亮亮晾览览靠靠净篮潞赂煤拷娇窘考梁鹿霉禄禄坷毫痪净阑阑炕阑兰烤究靠炯阜瓅,!(/577777641-)&#! $'$$7>;8<97<BHIFB?ADIMOMReu儘槫<E58498>安附苛侣侣亮晾靠靠靠览亮侣侣侣侣铝亮亮览览靠伎郝纺放仿季骄剂郝孤孤毫焕豢郊阑考骄季冀季骄骄骄揪究拷几i&-231/..-+'# "&(")2/+-39<=<;878:=@@==>AFO`w寽<77>埠铰媚寐亮亮览靠靠坷亮侣旅寐侣侣亮亮晾靠靠净抗粮赂梁考窘考炕阑考拷窘窘骄骄浇浇郊郊浇浇浇浇揪揪娇精(#*-,)&$$$#!!%((%" "&&'(*-.0//./0379:;;:9756>Nk<4E>不豪呐穆晾亮览谅铝靠靠纠旅吕懒揽究揽窘娇撩冀痪痪痪季浇浇浇浇浇浇浇浇揪窘浇浇郊技技郊冀浇浇揪焦富旿 '*($ $(++($"!!"#$%&&&'(),.134554226==42x棷瓶究聊寐旅拿晾旅揽钠拍呐镁构季窘究拷祭门萍技技技技冀冀浇浇浇浇浇浇揪揪浇浇郊技技患技技技揪净箍<E58780>&"&$ #'+--)$!$&),0368::8669<91>[尵钠巧坡靠亮拷汉坏到坷还壕缆剖木缓换狗父构技技技技技技技技冀浇浇浇浇骄浇浇郊蓟患换换技技浇烤浇矑W"!!!&*./-(! $'+/25789:;<=;78@g煼焊姑辆坷窘咳侨考美侣窘坷揪谅竟贩返镀扇苹换换换换换换换换换换患浇浇浇技技蓟换蓟换患技技季郊瓇K,#&%"#)-00-%!$(+.02357:;9441K{⒉汗<E29289>殯洍敃妱唥z}uskedffb^]WPKHHGD@;986换换夯换换汉汉汉夯缓夯换患骄郊杭蓟夯技缓汉夯蓟傅夯瘎I' $/:?:1)" %+/0.)  #&(*,.146752.6?@2310+)-,''+'!&"#& #"$),*)+1.+*++)(7:::换缓构购汗构汗父够垢负浇换纠净夯桓陡换汉垢犯阜刀懦奞%#-7>>80)#"(,..*
 !"$'*.1332052* "$%!#)' $$(/-0-)((&!!%*)(+010,'(*+购焊档捣贩饭垢档够苟豆浇抖航坏捶沟扯汗购父反脖掣綁K"$)*)'%#!#(++'
"&+/00.-($*%#'$(38044<EEMPPSZ`epy||~剨帋崣潯さ吹阜炒贩斗狗脖撤冻<E692A4>蹈烦澈富彻侥颈妇狡破睦壕<E79DA6>渾X.   ###"!!%&$
 %*.0//32f垥洓<E59EA5><EFBFBD>富浇韭撬侍杏兴绦栽淹弦匝瓮趟夯环闯炒阜附谰唤绕敬<E7BB95><E695AC>洆攪乶onj_KE:'$$%/-6,! 
 &+/0278嫟犊颗哪趴揪靠揪滥评滥汕粕怂松乔颂送吞坍斗<E59D8D><EFBFBD>槏垈ug]PLD90-'"!!"#*'$ 


"',0557暀┋案九赡门破拿钠木娇侣履热缮壬适适噬蒟ZTF:4.&"" /155-# 
 
 

 $).46;墮<>坷懒晾缕乔排魄瞧排拿媚迫仕烫屯趟适<E8B69F> )/2:@V`qny}倠嫊湡<E5AB8A><E6B9A1><EFBFBD>焑B+ 

   
"&*/26j挕不旅侣旅媚寐履破乔瞧哪钠侨墒颂烫颂趟"%498>IDGP[cjs€憶牎撤犯寐玫创焕付床侗<E5BA8A>.  
 
  
#'))&@q寽Ч苛亮侣亮谅妹呐排哪哪魄热墒仕怂怂烁贩复安睹量拷焊构骄焊铰酶毒究负换嫉脖隘<E88496><E99A98>畕(  

 
   #''",Nw灓醇坷览览览缆侣妹媚哪呐破侨壬缮适适<E98082>赋彻还捍背父斗搅粱负苛炯郊旱蹈汉洞巢<E6B49E><E5B7A2><EFBFBD>V 


 
 #&"&4`湥惫娇揪究靠坷览亮侣旅媚呐破乔热壬缮驳巢卑捶狗斗杭冀棵辆换蓟汉患悍陡父兜荡潮<E88DA1>棁;

 
  !!(A墷<41>菇浇浇骄揪靠览览谅旅媚呐牌破乔乔父阜抖负汗腹杭技纠拷换换汉换汗阜范创创幢<E5889B>抃(

 

 /d摛渤购夯患技浇揪究览览侣妹媚哪排排鸥阜贩犯汉汉汉患冀浇郊换缓汉汗父抖创吵吹氨瑨5
 


"C€洶胺父构汉患技浇揪谰览晾侣妹妹哪呐贩贩犯腹汉汉换技冀郊技缓汉汗父范创吵炒疮驳| 
 

(Z仭<5A>刀犯构汉换唤伎祭嚼纠懒亮谅侣妹父父父构汉汉换患技技蓟汉汉父阜兜闯吵车唱ィD 
 

 ">h嫰<68>撤贩父购夯航嚎嚎焕嚼坷懒亮亮粮父腹构汉汉换换换患换汉汗垢阜抖闯巢炒党<E78292>} 
 !"! !!"!   ?_洘Л捣斗犯构汉杭嚎箍豢伎究究览览构构购购汉夯换换换换汉汉腹阜范荡巢辈档播岾 

"$#""#%()$ !(-,(" 


 +G嚋Κ扯刀斗父构汉脊竟亢炕窘浇揪究构汗汉汉汉夯杭杭夯脊脊汗狗父抖荡帛<E88DA1>蛋疄p!   &'%#$&*/2*! !!"!!! ! !!""###$'/9>?<6-" 

   !5j暔┏反档犯腹构构还礁竞交技冀浇焦汗缓够杭夯患杭杭汉几汗垢狗贩档潮<E6A1A3>按┍<E68C89>;$
 !*($$&).49/$ "###"""""""""##$$%%&&'()*,19AGKMLI@4(       '?l湯岛荡捣构父腹构桓焦胶换换换冀汉汉夯夯夯夯杭辜夯还还汗垢阜兜闯<E5859C><E997AF>槞塋/)
  %+'%%(,16:0' #$%%%$$"#"""#$$%&'()*,,.04:@GMQSUURLC90&
  %%#Fz<46>径豆缓阜父构汗桓脊缓汉构患己夯夯夯汉蓟换杭夯汉桓汗垢狗范洞嘲<E6B49E>|vt[(,'  
&+'%&).267/' #&'''&%$$####$%%'()*,.147<AGLQUXYZYWRKD=4+!  &)1Q傅范斗够垢腹购够购购汉汉夯缓脊己缓患讣己缓缓夯够构构犯范档闯<E6A1A3>q}\4(.&  
&*'%'+/364*%"&)*)('&%$###$%&')*+-049>CHMQVZ\^__^\WPJF?5)!   #+*0彽恫<E5BDBD><E681AB><EFBFBD>饭构构构构杭浇娇技辜辜换还胶换换夯汉还汗垢狗范荡炊▄帎H'61$   &)'&)-1562%! $+/+))'&%$##$$')+-.049?DHMRX\`cddedca[UPLH>/&
  
)"t<>牏晲yu厽春汗构构构构级<E69E84>炯夯夯换换缓换缓夯汉还汗焊父贩兜创蛋~猳 NK0!    $(&'*/3995 "(34+))''%$##$&)-/138@HNQTX]bfijjjihge`[VSOE4)!   

' Z巼bU3FFo櫚患汗构构构构伐媫郴缓菇辜夯换换杭汉汉汉构购父阜兜创党<E5889B>+&fH) "&&(,16??=#-?:(()('%$##%(+048<DNVZ[^bgkoppponnlje_]ZVJ8-%
 

%( 8X`XK3BV挳芳己构构构购勾檥e<E6AAA5>杭还礁胶换脊靖换汉汉还焊父阜兜创亥<E5889B>.cC0$ $&).4:CCF"#7KA%''('&$#%',3;CJOU[_abeiptvwxwvutrohccaZL;1)!   
!+( ;HUMJNu┇椿己构构构杭挤泘c肪几技辜夯换嚎毒汉缓汉购父垢阜兜闯氮<E997AF>/J8*# "%)06<EFJ*!$CPH$&'''()+.4;CJRWZ]adghlqwz|}}}|{{zwkeidYJ=4-% 
'-&#3FPEBLx哎不己构构构辜澜甌L竟杭夯杭航辜椒婪蓟汉汉汗汗父贩洞炒節I:4/*#$*08>EGJ1! -GOL'((&').3:BJOTY]`cfiklqy~€們儌亖€倐nkoaTI>70(

 )+),8D8BDw灕椿己构构构航揽礧L阑脊镜链蓝亢壕毒汉缓汗汗垢垢阜洞扯硏1(920'#")08?CGG3! (@JNK-,+(&(,4<DKRY]acfilnry€剢垑墖唴唺峬qqZPKB92+"  "(**+50='a摪痘缓构构构杭揽竘S豢壕疵材裁督还竟换汉汉汉构父父兜捣終*I@2,&# '/8>BFC2('?[VQK8540,)+1:BIPV\_cgjnsz儔實彁弽妶嫄昹voROOG=5.%  $&$',4(z犯负缓构构构杭靠簯i嘎汉椒赖麓抗蓟夯缓缓夯负汗父父阜贩繤8H<2-*#&.6=@C=4<C_maVOEA>;72017>FNUZ_dgkq{剫彃晽槚搷姀暅nvjMQTL@71)
  !2=<3D>斗汉汗构腹夯季拷硩耗杭夯杭妇汉杭夯夯汉汗缓构构腹购构<E8B4AD>?MD543.#$-5<>?=E^isnc]WOKGEB>:5227ANX^bcjw剭憰櫅潪潣悑憳漵peNTXNB:5-# 
 G<慷抖购构狗还夯季窘晶宦敬栏焦技辜己换夯夯缓购汗构购患夯<E682A3>.QC69;0"$,6<@BK]ptqida^YTPNLJHC=505AKPWbv啋棛湡ⅲあ潝寫棜zibQWYO@<92(

 +]?碳复腹构购坊夯冀交嫉祭壕房毒几交夯缓汉缓汉汉汗构杭技兜|>R79?@. ! "%-7@FP_ioomkigda^[ZXXWVWTOMRW^k|摐牎。ェЖΒ槑悥梺h`VYYL>=<6.% 
  8WB殴党豆构狗挤缓患交缓季航富己杭缓换缓汉夯汉汉构购唤换<E594A4><E68DA2>>K3>D=&&)(&%)0:DM[hmqrppomjhfdb```accejs}剫敐ⅵΘ┆<CE98><E29486><EFBFBD>憪晼噉aZ\WF:@>:3+"
  "3RD<52>闯陡构购芳讣患蓟换冀几胶患辜换患缓购夯缓还汗购唤垢攰<E59EA2>?D5>@1 #031/.07AKVclpstutsrpomljihjmrvy~厡憰洟И<E6B49F><D098><EFBFBD><EFBFBD><EFBFBD>棑枛峸d^^U>7DB=81)   -IA<49>渤陡构垢焊脊蓟换换技缓焦换蓟换换浇汗夯换夯构构冀复巶|D=696#  -9:888;AKU^gmrvwxxwwutsrqpqtx}倖姀暀潱Й<E6BDB1>氨辈巢伯<E5B7A2>棙槕~ia`S68JFB>80% 
 )?>倒背陡垢腹够附夯换换患壕肪夯患换汗菇竞患换缓汗购技番憜zE920)
(7@@@CHMSZaglquy{|||zzyxxxxz}倖妽憳潯エ<E6BDAF>氨吵吹档幢珷洓殧俷faR3>PLHGA6+   (:@胶背犯父父购还唤换换换几抗换技换汗堡换技技汉构构蓟窛拤w<6+* 
!'4BHJLS\dinqsvx|~€亐€~~~~亙唺帒敊煠З<E785A0>安车抖斗范钞<E88C83>灊棃ukcQ6JYUMPN@1 
 %9B炕车父父父购夯还唤夯换壕富蓟患蓟换竫<E68DA2>骄技缓构腹己矂噭s/3&#

 $)5CNSWZajrx{}~亙剠厖剟儎剟唸妽悡枡灒З<E78192><D097>炊斗犯父付皑<EFBC81>tiR9WebRVXK8#
 6@换炊构父饭够换换脊蓟换几交夯患技己簗骄技缓垢贩还<E8B4A9>u~w'/!
  ).5GRZ^afmt{亜唶噲垔墘墘墘妺媿帎摃槡潯ォ<E6BDAF><E382A9>炊斗腹构构烦<E69E84>ぃ灁<E38183>t[=`opXZ_UB(
4=稻捣构垢腹辜换换航汉胶咕购蓟换技蓟耿Υ冀蓟汗阜兜焊榁l~&)
 -8>K[`dhkqy厞崓崕帋弾弾弿彁憭摃枠殰灎<E7818E><EFBC87>驳犯负富购垢串<E59EA2><E4B8B2>枍噣mB_tz]\d[K, 
2;戳捣垢构汉肪缓换缓患辜礁患夯夯换患几车杭蓟汗阜荡勾橵o{}(&
 1HT\hjhkrx厞彃敂敃晻晻晼晼枛枟槞殰灍。Θ<E38082><CE98>炊父悍礁汉垢当<E59EA2><E5BD93>槕寛€QX{卋[icV0  .2航斗父换但<EFBFBD>缓换换缓己购脊换汉汉汉换垢够缓汗阜党覆焥qov)%
Ngpopoqv}儔帗枠櫄殯洓洓湝湝洓洓湞灍、うí<E38186><C3AD>刀负方芳购狗挡<E78B97><E68CA1>湑憢噃Gv巙Xjj_6
!6<冀锤阜几攊<E587A0>构换换换夯辜购还缓汉汉汉构汉汉构阜荡赴<E88DA1>zqq*#
 &f~~wvx|倗寫暀湞灍煚牎  <E38080>牊灋灍、Ж<EFBC85><D096>背捣垢挤脊还狗党隘<E5859A>煔枏妧O`僡ipi>$
%;D都掣贩蓟峈<E8939F>构患换夯缓焊汉够购汗构构构购汗构父洞赴<E6B49E>yqn,"
6s噦|~儑審挆洖牎ⅲ¥ゥゥゥイ牋牎ⅲェí<E382A7><C3AD>贝斗腹够汉汗付党悲<E5859A><E682B2>洉崑qV`€rlurH-  
&;L<>倍斗椒圴懊腹换缓还缓购汗桓汗构构构构构构构构洞喊瑵wpp4$
 Gz崊儐嫃憯槣牏¥ゥΗЖěΗЁィЖ<EFBC85><D096><EFBFBD>泊捣腹汉汉汗范床悲<E5BA8A>ァ煕拲噏YutputQ8   
'?W<>炒捣函搰寄父换汗购购垢构腹构构垢垢构构构垢购<E59EA2>撼盃|sr?+
U悊垗悡晿湣ぅゥゥウЗěイいぃ<E38184>牎うī<E38186><C4AB><EFBFBD>泊刀腹汉汉垢返床爱<E5BA8A><EFBFBD>檼憢zqikooTB'  
 ,C\棻党捶矾<E68DB6>铝腹夯汗构购负饭父构父父负腹构构狗苟尡焊疅倄sK5
!^剶噵悡枠湢うぁ牎 ·Жァ牉潨洔灍牏ォ<E7898F><E382A9><EFBFBD>安车斗腹构阜返床爱<E5BA8A><E29482>槙槖塳fifUG0   !,BZ叄党捣烦祷郊腹汉垢贩购阜狗垢父腹饭父汗构汗狗激Pご户棄倀Z= 
)e嫎垗摉槡灑あ洉枠殮殹èァ灈檿憯棙殲え<E6AEB2><E38188><EFBFBD>氨炒刀犯阜洞脖<E6B49E><E88496><EFBFBD><EFBFBD><EFBFBD>殫櫆湀qpgWM:$ 
 )?X}洿贩贩捣够汗购汗党饭悍狗狗父腹腹腹垢构夯汉妨o`ザ鸡崕恮oE&
 ;d崣垙敆殱牎灀噭唵厔唵xpmiiimrz儔寧摑Κ<E69191><CE9A><EFBFBD>辈炒刀兜潮<E5859C><E6BDAE><EFBFBD>潩ⅲ灆棗櫆枃€ueWG1
&=Us帺负父斗腹构购焊嘲豆焊犯犯阜腹饭父构购换旱兜X姲菇獘嫏wX3

>c帢墤枡湠灅寏sqqojggcRJE@==AIVjx亗剳牕┆<E78995><E29486><EFBFBD>膊膊碍─煘煗洐晵暁殮湜棎帍挄攷墌n_P=' 
"3Q`o〉还阜犯构购换懂<E68DA2>够贩犯犯饭祷豆构构杭几唇塯<E59487>妇睆倴墈lI%
  ?h彇寫枡洓攨uib_\VMGDB>962126;CUgtvt剹ⅵ┇<E285B5><E29487><EFBFBD><EFBFBD><EFBFBD><EFBFBD>{tnhaZW_mvy亝}z~儓媼寖ufZJ6 $COE煹己垢父构夯蓟川┒夯贩阜阜勾即焊腹购唤挤慷V櫤<56><EFBFBD>實|s^8  >n彄崘晽晫~nc]ZYVPIB>:5/+)()-4>IXcidz帥<E285B4><E29487><EFBFBD><EFBFBD><EFBFBD>弫uneYOHBB=;>ACM\hov|€剤崋{maUB) "1M+《技还构购患己阿Ц患阜贩父痘椿犯构夯冀脊縹Z环昂骄珛姀~smQ0 <r帍帍挀媩lb]ZZZWRLFB<4.*('(+2;DNWa\s嚂潱ǐ<E6BDB1><C790><EFBFBD>棈乸bZPE=84642/029CNW_cgnz妶~rh_P6 
 /%J,ザ患己汉夯患己疄Ω冀父犯父付憾垢构夯缓缓烪惢驳杭镜爾晙yznS< :x弻帊悗剈ic`__]XPF>9753211247<CIR\\p€彋牔<E5BD8B><E78994>ē<EFBFBD>p^PG=3-(#!"$%(,16:=@AEOc~剙wmh_E& 
&9 6F<36>杭交换换患还瓲Ч冀父父父父饭父构汉夯匠j_陡倍够几<E5A49F>潅倖厈Y3 8}悏弻崐skgffec`ZSMJIE@:63368;AFNY^o{嫍煢<E5AB8D><E785A2>В灂媮reTI@70*&" !#%)059<>?CPmy|xqmhR1

)5#{倒航郊蓟换换狗<E68DA2>└骄父父父父父父构汗估臒L》钩饭换复瓱剦彁揾@%
4~巺寠寘yokjijklnqv}儌rdUF90-/4:AGR[nx垪煣<E59EAA><E785A3>В湊倂h[LB:3.,)%##$'+059<>@AA@DXjvwsqn]@


%-+淳窘揪技患缓狗串К菇扛父父父父犯腹购构疗tw档返腹汉苟皾嫃槣漷A/! 
0}墐墘媬pkiklnmnpnikmoq|zqaJ1)*/6>ISjy嚄牘<E59A84><E78998>─潕{naRE;510.,)),-15:>>>@ADECBM[ltttqcL   
"5#T赡量烤郊蓟垢洞艾<E6B49E>航靖腹父父父父腹购父沪i礁饭夯还凡灀摕<E78180>塏2,(  !r厑唸塹hilopokffaUMBAPWTT[\M<2//3?H[|嚈‖贝杯<E8B49D>潒tgYH=40/* &,--/48:;?ADFFELXepturdS&

 &! <1D>辆烤窘蓟狗床<E78B97><E5BA8A>澈娇构腹泛犯贩父构汗汗彁坊竟购换缓狗<E7BC93><EFBFBD>歞21D9
h唦剢~W]ovtpjbVM<8Sr嫓殝oWONIB=73:BLt啘ぎ蹈恫哀潏m]M=3*&%$15==832215;@DGIHMXcmsvsfV)   勄坪唤窘蓟苟嘲<E88B9F><E598B2>岸冀靖构负豆犯贩父够娇矟犯换购换换缓共<E7BC93>┉牆w.-YZ5 Q亀亗rG{<7B>rlbT<7Gj帓媹yfUQNMKJHE>;?Ed儬Ρ航欢胆檭dO>1')=MUboqneWM?69?DHJKOZakruujV-  
'#j斄脊唤浇缓傅悲<E58285>安倒冀竟构狗狗付抖斗够胶煵挤购换换换缓憾<E7BC93><E686BE><EFBFBD>w+'ZoP4pt{kQ6儜~mh_C5Pv€hB0(")AJHJKLKC?EW~步晾换<E699BE>|X>1+*,;Yu儀d__ailhcXG@BGJMNSZ`jsuxqV-
  f劅焕夯技蓟焊范兜斗腹冀揪构垢狗付抖档豆构⿷阜逗患技蓟换汗栋┉<E6A08B>峚-'Hi^7#+&NfmV`4唻zmfU;HkdB.%%0P?" QUFMORTODLNvΝ道琶览<E790B6>pJ3.,1>Zpn^RH?<>IWcniQA=DLOQV\]jtuywX+ 
Q<>概炕夯蓟缓构购汉夯冀浇竞汗垢狗范荡车狗畳暩蹈患郊蓟换换悍<E68DA2><E6828D><EFBFBD>L4/5O[Q:,!97*8DVT6寗zmdWCNTC?N@&() nmGKSY\]RSTlУ臼退抢異e>457K[e^NJL:##"!+?TZWI:<JPS[_[guuxy]+  +惿暇铰交换蓟换换换换技浇娇胶汉汗垢范床背副焺<E589AF>饭患蓟换换换悍<E68DA2><E6828D>泎G<<3<M[OA8Ko5"'p@7攩{nd\OFDJY[E-$23€刐NNUbkfUjj熀朴肿智祿_<:@Ke`QELk\& 01%/E=GRC:GPT_f[btxuwd-  S汗<53>纠交患患换换患技浇浇考竞汉购父返潮按寒枏督父够换汉患蓟苟哎<E88B9F>瀢RIMNNJVZSH[剝h.|;M搱~vmcZUV_feU?513<W妽oe`fpwqho儬灕缕嫉郸嘳@<JaaMJK[卭(!(\:.DF>GPTcnb_k|wxg- &6漂<36>揽郊技技换换蓟技浇骄娇竞缓还垢返潮案氦崶焦创泛技桓贩贩兜勃<E5859C>瀦b]gqwngc`Qy儏<79>;卋g槉厓€}xsqrv~噯pdfmx垖噣倕寘<E58095>:945GUUZ[TNRA7Dk{bSU`s崁2'!";kN25<BKPSfrphXwzh0 ."来捣辆郊技换蓟技患冀浇浇揪净杭够构付巢尘穼嵎礁吹返档腹壕焦兜钞<E5859C>泑nnz噺剅hcU!弶儢@~vn泹媼墕亅upmmt亸憮悐崚搼憫挃{<7B>)ey摠瀻媫oWYD+Iqzolo|噽岻3215=Vm[E98BMOTkxyjJZ寋n6 #(+,交斗澜蓟患换患换技冀浇骄揪净蓟己汗阜闯德猵牸骄档患炕礁炒<E7A481>┋膊悲渷wv€崜卹e[U(憫墮Y€唚檹彃搾崉{tnicafiigksz}€厠悋w<E6828B>(`惗淘谲谈唓_&Vnz剟剨審損OC96JjrcUJEIOS\r~|pVG妔Y, #,+c煽贩炯蓟换患夯患患冀骄揪究炕技蓟缓狗党到i布及俧cbjtwi]_es懍荡脖爢{|厰攦oaOQ9悧彎姍啌憭晿様寔wrpoopplhhklmr{墝||r$y谷人汕桥潅]'cp{寘噳垐媼憴棈垉p`URU[`cn<6E>vIY乯-* %+%;痉坊换换蓟杭换换换冀浇浇骄交蓟蓟缓复车県嵓患盃<EFBC90>櫁煥不还冻肠<E586BB>倞槖俴]IHK摓挍妛<E68C8D>搻摌湜槗妦sliiihfc`_cp}啀媻Lc3壙氖仙那搂欳+Ygz媴垍€yrplga[^a]ZZ`mz{y€姀厁B`I="<#&%"}铰冻垂夯换杭换换缓汉垢抖斗购冀唤技蓟复犯<E5A48D>独锤膊附礁吹饭阜斗腹反惮搫垗槕乮^NIV枮挅孿湧殣挋煙潥枎乼kd_chmt|垞棗攼<E6A397>:_U櫪认盐敲绩<E695B2>;1FP亴妿巻xiaacfhgc``fq亴寠帞晫wTb1' 2:"$"(Ω悲<CEA9>饭缓夯够换换汉沟<E6B189>Ж<EFBFBD>苯痪冀浇挤彻瓋傅兜缓垢负焊犯汉垢负焊档瘶噹彇悂iaZVg暀挃攃v敂槧牊湑崋倐墛姂殶煗湚櫃pGk<47>释烫肆滑滼4;=帋悞晳僺e]ZZ]]_diq{垚挃棙棎dZ?_XH($ "' )ク<><E382AF>饭汉还缓夯换购憾<E8B4AD>煙。<E78599>炯浇骄椒驳恎背坊季技换技唤揪郊蓟焊档矟墦挄憙necn潣挃敆區ǔ崗殲ぅΗě<CE97>牊湚殱牐ΑpC|<7C>鞘颂死韩燷4FY殣摃槝悈|qia[Y_hqz啈槢洓殫悂p_Noub+26541./9>!<o惄泊泊饭夯讣购夯冀阜己桓铂А熅痪浇骄靖腐b澏<62>窔蓟饭换技冀浇技缓傅挡<E58285>槙棔唗nr尟憣晻敆崊噩崨湤エ<E6B9A4><E382A8><EFBFBD><EFBFBD><EFBC83>>y摣睹商紊抗珮~;Us湑晽洑枑寢垍儏崝枟洝ⅱ灈殩恾僝q厒o;!7=FNN@<E`~潤Ο范刀腹汗几汉汉痪龚炯沟<E782AF>灱窘浇娇径秾t辜卜﹋痘逗换技技技技缓付挡瓔潥殬<E6BDA5>垻畧垟棓槣Z撥煝殰ˇ<E6AEB0>北爱<E58C97><E788B1><EFBFBD><EFBFBD><EFBFBD>梾Mp嫅<70>寥舷染伐晪VZ枟枤灎灉湡牊煟И<E7859F>īВ灇棏寢匤厡zsN$6=HYaA<Vx煪毃<E785AA>付腹购汗缓汗够骄<E5A49F>稻夯覆ā浇浇浇揪东pし环稓`负逗换技技技换汉付当矏、灉晱摐<E699B1>啌枖棤枅y嗜瘺灑Λ<E78191>鞍隘<E99E8D><E99A98><EFBFBD><EFBFBD>峃v<7F>廊蜒萍担様yl}晽枩ΖΖΗΗ<CE97><E29487>Β湕晱晬b\槖俿\+7?L_gHBnn枮灒<E69EAE>垢腹汗汉汉构够嚎<E5A49F>*灪缓捍<E7BC93>窘浇蓟玖緩}惫贩硿偭阜夯换换换汉汉垢返贝枹<E8B49D><E69EB9>湣Λ泏剱晵敍湚哬<E6B99A>禐煟ЗЖ<D097>氨北艾珰塡唹厫灟毫捎优共<E4BC98>攪}o彈槤え<E6A7A4><E38188><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Α檿搸憢H彎厊sc97BRejMPhH悺<48><E682BA>垢父购购购构够痪笿嵒缓旱<E7BC93>浇浇换颗礯湹阜凡<E9989C>姆负换换缓汉汉汗父恫礇灜┃ゥЖ<E382A5>w倣搼挅潰枈tα<74><CEB1><EFBFBD>ō卜范繁<E88C83>峸櫊儕敜臣滤栽歉埃枏<E59F83>e|悧灔┇<E78194><E29487><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Д灂憫枺檘拞|tfP;BUjmJiL€ⅳ牞饭垢构负购汗构痪椒櫁靖购诞ň浇交豢脗]苯豆洞坊痉负汉换汉缓汉构垢返碃敨<E7A283><E695A8><EFBFBD><EFBFBD>y€嫅悜敆棜攷悅椆咸嫉讣拿欢<E68BBF>帊槡寪櫄<E5AFAA>颗握杖腐<E69D96>悑僲q亼湨<E4BABC><E6B9A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>В<EFBFBD>棊帓珱Ow倓倈thiDDXnpQ<70>1\洠<>腹垢构汗汉构购痪椒奖几购动<E8B4AD>浇交搅絃樅脊沟蹈汉父汉汉汗挤几汉构父反<E788B6><E58F8D><EFBFBD><EFBFBD>攟~垘彁摉枛枠檿剗儧钙舆阕粸憤悧棛拰棟牤宦尚种斯唉洅崍{vy倯Ο<E580AF><CE9F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>牊煋彏槷K寪倓亂pfzPK_sre<72>.嫭购父购购汗汉汉唤礁换还构繁<E69E84>窘浇烂礢祷附苟斗父腹购汉辜方都腹构构苟瓝槳<E7939D>豆勃渶{唺寧憯晻晼櫃拹摍ˇ┈<CB87><E29488>殮殮棖憭洜Σ酒逃字秃畅潟帄儈~}湵饱エ<E9A5B1>èΔ瀿帴<E780BF>贾UWv€唦€|tkf}YTitp亀K<>祷还构购汉够购汉换购换构垢<E69E84>揪浇桓皸J洺壕桓斗父腹构购焊级椒汗垢腹苟啊棫铂备传瀮v倗墝彃敃敃棗晻槢潪煛¥<E7859B>洑槜晸挅灑ù郎卧刂位传<E4BD8D>悑唩亙剬ê睜ⅶГ檪棳肱Xx亷|}||wohj}``rpi扝 !x卜郊构构汉讣富购汉汉汉汗父丁幗浇焦椽<E784A6>?Rb~湱刀贩父腹构负焊挤焊父父垢弹<E59EA2>┛卑礁<E58D91>剆~剢墠彃摂晼枙敄槡洓潩灉殭槜枖摂櫊睹萄兆治嫉<E6B2BB>殦巿個儑姈熀平啊棔棙櫘<E6A399><E6AB98>鄩\啇寙{{{xrljpxflxnn<6E>" W倒窘汗构汗挤椒还汉汉构垢贩穿⒔浇浇玖榔莱扯贩贩犯负饭构负汗汉父父父苟<E788B6>煋碍ň澜瑓ty儑嫀悞摂晼晻枟槞殮洓殭櫂棖晹棡う<E6A3A1>耐言衷尉懂<E5B089>様崈亯嫎<E4BAAF>}lu倞憰巘MQo搵z墖€|zzxtnjkqtox{nwl  k杭烤汉购夯妇毒坊构构构阜陡焦督浇究僚禄犯苟档斗犯付环构焊汗汗垢阜犯构伯<E69E84><E4BCAF>湦膊<E6B9A6>qsz~儓嫀悞摃晼枟棙櫃殯洑殮櫃槜棞ぇН改滔延彝糠<E5BD9D>牆洉媭墡棜帞殯枔敄枏巣<E69E8F>}€厑~|zxuqljkrv{zo凙?壓嚼胶汉汉杭附芳负汗构垢贩患爣窘浇郊技交构范抖贩犯憾桓构汉汗汉父贩饭憾<E9A5AD>@V塿lknh__ksy剦審憭敃枟棙櫃殯洔湝湝洓殰<E6AEB0>胺辽掏瓮士贡<E5A3AB>煙煏<E78599>姁晻敄槝棔晼晭妴垐噞€~{xurnkhlu}剙z€<7A>$ |挼娇交换夯够还还还购构狗贩罕_娇浇郊缓反膊吹抖贩阜泛坊负购购汉焊范饭换躬>)Votd\YVZhpt{亣妽彂摃枟槝殮洔潪灍煘灊潬┉<E6BDAC>岸灸巧噬瓶共<E793B6><EFBFBD>崁寫晻搼憭挀敃攽帉媻坿~~|zvspljfo|厠亝憥N敇凹窘蓟换杭够汉汉购构垢阜饭磼}拷窘郊焊兜吹抖贩贩犯阜焊汗购汉夯己阜负汗焙抦QEay個pkmqrw~剤嫀悡晼棙櫄湞灍牎 <E7898A>┋岛柯牌泼靖报煔櫉爼亷晿棓拺憫拻摀憥寣妵~}|zwtqnkjbv厡拡搵V
0創“唤郊换杭辜够夯汉构汗垢贩够<EFBFBD>娇揪交悍荡刀犯贩贩贩犯饭构汗购夯窘阜航脊闯<EFBFBD>]17D[ntzutprz亞妽悞晼棛殯潪煚ⅱい<E38184>ˉ<EFBFBD>湬岸夯季谰捍<E8B0B0>棎彅殨亹洓殩敁拻拻拻悗寢墕~|{yuqnljj]{垘拤杹% n<>“航郊换脊焦几脊还汗构垢父构抱烤烤窘烤憾捣父阜抖抖贩犯购汉汗垢宦拱防炕窗<E78295>c)+  9Myyqqv~剤嫃挃枠殯潪牎ⅳゥΖΒ潨潧張槪<E5BCB5>鞍车窗<E8BDA6>晞y|厠<>憻灉櫁晹摀拻憪帉妶<E5B889>|ywsolkieWr{{寖] `槹┇彻技蓟焦竟礁靖几几桓焊垢父复<E788B6>靠烤纠侗<E7BAA0>捕抖档荡吹斗腹购汉构董<E69E84>人两繁帆|[;4 &i乼st{倖妽憯枠殰灎。ぅΗЖá棊厏m^j摛イЖΒ湈y`V`nwy悺牆洐棖晸搾憪帉墖儈{xupljjg^T`pz亴S(<櫗超<E6AB97>够技脊靖胶几礁级蕉降桓父阜嘲揽揽净禂噣垯Κ<E59EAF>膊膊吹犯构汉汉汗磿s嚛醇舶藩刕B;(@vqtry剤寪摉槢潪牏ぅΗè┅爺墂kXIM[r崚挄攷寘lN:7CUcss師牊潧櫁枙搾憦崑墕倊zvrmigjg__q|uml2"g\<><EFBC89>够技痪妇汉换辜妇蠢尘岛父付碑懒亮焦瘋fal倴々<E580B4>鞍辈炊饭汉换缓苟矎<Ng埄画瓑i:>-G+btsqv}倖嫃摉櫅潫。うЖ<E38186><D096>煈噁O8.+/GeqtxupqhF+#%0DWmq対<71>灊洐棔敀憦崑垍倉ytpkeflncfliQ8!,V櫅q牑<71><E78991>够技脊竞患辜汗级啦敛椒父付<E788B6>亮亮交穾NQaw嫓Μ<E5AB93><CE9C>安捶购患己还交<E8BF98>CTW^灛箳`KO6O$Fupty剦帗棛湠牏Θ┆<CE98><E29486>拵iI:2-)1ESX\ZYXM0"!%.ATku帨ⅱ牉湙槙敀憦寠噭€|wrmhcgrpOG>&3啰罉嚙Θ<E59A99>倒换蓟交患夯换汗酱啦慷焊阜淡Я谅陆伎濦Oew姕Μ<E5A795><CE9C><EFBFBD>炊购患己淮<E5B7B1>瞷FHKBZ姷焁fq&2(€ursw}倗崚枤湠牏うЗ<E38186><D097><EFBFBD>晼wSA9632;CGGGGE>1.129I[o|挐<E68C90>湜槚敀悗寜唭ztojfckud'"_潯<5F>灚ī<E7819A>豆换蓟蓟蓟航讣夯附纯椿父阜惮チ侣媒焕燞Zr€憿ǐ<E686BF><C790><EFBFBD>炊负患胶即境朾ZJ7&8帩mb<6D>(#zuwvw{厡憱殰煚ⅳェ┆<E382A7><E29486><EFBFBD>瀸lWKJHA===;;;;;<ACDJWgx啒牓ぁ煗殬枖拹帇垍倉xrmifepvN x<><EFBFBD>ī<EFBFBD>逗换唤杭脊康炼己桓级挤垢父船ち旅慕寂濺Ri{懁Й<E68781><D099><EFBFBD>炊负患己悍z彻瑏qa8+C€}f<>, #hw{yxz}儕悤殰灎ⅳΗí<CE97><C3AD><EFBFBD><EFBFBD>噋`XUPG?<;:::>EKPU\hw啇潱Δ<E6BDB1>潥槙攽弽妴<E5BCBD>{uokhhgr|(
r<72><EFBC8A>í<EFBFBD>逗换己冀仿衬擦负汉购负父阜船ぢ旅沤磕<E6B2A4>9;Xn姟<E5A79F><EFBC88><EFBFBD>扯腹夯缓构У矾晍](!*;[k<>(+ Wt|}yy|亪帞槣灎。ェ┆<E382A7><E29486><EFBFBD>Α枅{qi^RE>988<DOX`hoz噾槨イ 灉殫晸憦寛剚}ysmjjiksv
P敒朝<E69592>í<EFBFBD>逗患患椒虏挪牡交够购腹垢付倡っ媚啪铝僀B\n垵牔<E59EB5><E78994><EFBFBD>车腹夯缓够构钩▇HLGU劅!35>x}~{y{啀挆洕煛¥Θ<EFBFA5><CE98><EFBFBD><EFBFBD><EFBFBD>vk]MC=:<CN[enu}啇棞ⅳ!煗洐枖拹帇唫~zvpljkknr_  ,l嫴<6C>è┉岸夯患还赖么麓抗杭讣坊腹阜恫<E9989C>妹呐韭<E59190>\Rbn儣湥<E584A3><E6B9A5><EFBFBD>车饭购汗构父挤磭O#`T^喆`+AR7AHOz|~|yz~剫憰櫆灎ⅳェ┆<E382A7><E29486><EFBFBD><EFBFBD>檹唦tfUKECGO[gpw|儗敋灐ⅰ煘湙槙搼弽墑{xtokkmopn;
Q叒<51>Ηǐ<CE97>夯换技咕妇缚富几椒椒焊阜当<E9989C>媚排搅線JMdn}帞灙<E5B89E><E78199>俺刀腹购构父富阜攐J"$a[v}灮FAs巹弳v}~}zy}倝帗棜潫牏うЗ<E38186><D097><EFBFBD>殥媴}p_UPOT[fpx}亣悥殰灋灊湚槚搾悕媷倊zvqmkkorqi o殼<6F>いお<E38184>够患杭换换蓟换辜方痘饭贩幢<E8B4A9>媚牌伎紏MOcir亰棬<E4BAB0><E6A3AC>安刀腹腹构父负憾歿V-,Zm億兗奊s垊<73>亐~{z|亣寫晿洕煚ⅳェī┄Δ<E29484>殧強剒kc_]`fow}亝姁晿櫄殮殬槚敀悗寜厐{wtpljmrvu` !<><E68783>灋ó逗换患换换换换换够富腹阜反皑呐萍竟uTUccgt~彜<><E5BD9C><EFBFBD>刀贩悍汗父父即檧]B3Feu}彍怸r<E680B8>8~厑€}z|€厞彃枡洕灎ⅳウΖ<CE96>湗晳帄剒tpnosy剢墠悞敃晼棖晹搾悗寠噧~zvrnjjowzvH -'枻牬瑳摋ǒ泛换换换换换换缓汉还汗父反哀犆呐墙级n]Ya_cox姞í<E5A79E><C3AD>捣饭痘负汗父匠煇vPB9Rl寗~<><EFBC8B>厡們~||儑嫄敆櫅潪牋ⅲ<E285B2>潧櫁晸拸寙倊}}亝墜寣崕帍彁憫拺憪弽寠噮亅wspljkqzxn*   7NРΧ珨姇<E78FA8>负换换换换换换换缓汉构父反哀犆呐凭汗nYS\[anv厹Θ┇<CE98>炊贩坏汗汉垢话<E59EA2>卐N:?Lw剘姕篂D i<><EFBFBD>}}倕墠悢枠洔潪灍煘湜櫂棖敂敂搼弽寢實帊寣寣媻妺實帋帋崑妵厒~yvqnkikpytf
!"Acu俺<75>獥枺捶购汉汉汉夯患技缓汉汉构垢返唉犆媚偶患kPN[Zalr~槬Θ<E6A7AC>驳贩苟挤汉汉腹獟<E885B9>|UD9>Sotx€慛 A巰<41>~~亙唺崘摃棙槚敂敃棗棗晹憪憫摂棜洑晲寜垎唵厔們儍儏噳妷噭<E5A6B7>{wsoljhkpurk '@3;o﹙Ξ<EFB999><CE9E><EFBFBD>构汗购汉购汉患技汉汉汉汉垢返唉犆媚暮骄oKL^\cimw敚ウ┊扯贩泛逗购汉贩﹜<E8B4A9>tQFD:EV]_YO #€<E282AC>~亜唹嫀悜憦墐€€儑噰垐垐噯唵垙槢殨搶厑|xwx{{|zvuvx~儎個~{xtqnkiijpssj 3T/@摳w澃<77>辈豆构构垢父构垢辜蓟贩父构汉汗返唉犆媚墓季|QObcgjkw悽ぅó扯犯阜桓购汉贩畊<E8B4A9>mUQP9BJKF1i{坿~€亜唸墛妵倅nggkswwvtsqpqstu~垔剒ulfeedeee_]YTTV^jw|}|zxurolkiijnprT .WN€拱{⒊驳吹贩犯犯贩兜附降吵蹈负脊贩够缓付哀÷媚墓构奰Xfkkkk{悽¥Л捶犯腹腹构汉范祦カ俶oG6:H?-  Px剕}~}}~€們儌yqdULGGNTX[]_`acdbahqqka\TQRQRQOJA?=;>BIVhrvwvtrpmkjiiilnm3 H捄酱u<E985B1>炊档刀贩贩恫<E8B4A9><E681AB><EFBFBD>戮骄焊季苟泛己苟报⒚媚暮沟峧cnqmkiz懀Ν蹈父腹父构汉范穽灖墌t409E0  8wzy||||}}~~}ysj^PC<536;BHMOQRRNHDHMMLIMKJHEC@;4-,.169=IZgnqrqomkjihhgknk  )淮脊z┐抖档抖贩返喘い<E59698>tfmy嫙Η<E5AB99>悍都良悍暴⒙媚没降噅ivqigfr帰陡构父父腹汗贩祽敁|乚13E:  
!tyyuzzzyzzzywrld\TOOMJOXadaYROOOKBA?;==?EKNOSUTWTYbkpja[\agkmmlkjihhhejkc牡惀狈返刀贩犯反爱<E58F8D>僛>>CIMF@P€暆枺两脊暴⒙媚戮凉xdl|necdm垺 …负构垢垢腹够构皨唦u€R?GO* guwpvxwwvvutrpmlkkpy~~}|亪垉}|}zscZPEIP_nyzy}}xrnt~唵}tnhefhjjjiihghfbheI 
F潽<EFBFBD>┉蹈档斗犯父父弗慿M44:?DDGUm噈w每亢暴÷媚驴拷_go}kaadm劅<6D>煭够构构构构患垢▋|srxWYh>
 Bstkrvutsrrqpppty亞帒拺寠崚棛煣<E6A39B><E785A3>暊槕摍湝棏寘~}倞崏<E5809E>xohffhhhhgggge_hj 

Lw~姙ガ卑撤垢抖犯翻卼`I2-/13=RkxaJ橇亢哀÷履驴几Xipxg_afq嚒<71>湰夯汗购构腹技沟<E68A80>~tqrcfg#  ,eniossrqponmnov垙敆棑帇崙枤噶话贝<E8AF9D>煚煓憟倊|}€厙噯亅sifffgggffffd^cZ 5TWdz噿槥<E599BF>净陡缓睜{oh\T;)'-?j挄攰pW撩竟<E692A9>犃履录话adkmc]bex帲<78>毈杭阜犯父泛挤珶搯|rlkhgV 
Ndfmqqpommlkknv亯帒搾弸垎厙姀晿湞櫉<E6B99E>殯洊寖|yyz|}亗個|tkfeeefeeeefc^[?*C@BS`kmk{柇船<E69F87>戮珚€|sYA6<?Fc啑潠墌该欢<E8AFA5>×僚禄酣n^_b_[bh儠<68>枦熬亢党富狗共瀰nimmheggd;
 8Uajnpomlkjiimu亪妼寠垊倎€~}剦帍悤槙憦媴zyz|{zyy{}}}ztkeeeeedcdde`ZL$ %@=:@HNOEG]|寙€倿唇春缕泛览挤舶<E68CA4><E888B6>凹没惮Β览瓶换<E793B6>ZSZYZer嫏煓暍噶罚晲暃殬棆wcUXacaafc[ 
'GXeknmljjihhlt厙噯儉|{|€}|~剤垏妺垊<E5A6BA>|xvvwusppqtvxywrkfededdbcc`YM4 ?@:>CHIDBIT[[_g~槺附狗咕炕兜刀杭冀烤竞喘Г览浅箍爌YMUWcs崢殫櫐船憉njimqpnkf_^ab^Z^e^N 
8L]flkkjjhhhlt}儏剛xqkiloswyyyvw{~{||{xqib^]_aejnqsuuqkfeeedbaa_YO6  <C;>CGGDCGMNJKOXd仢<64>牏Σ懒患览炕构腹赋<E885B9>だ琅櫙锚oZMZgz儐嫅晽殹<E699BD>qaeiggffffedca]XV\f^=
->Q`hhiiihhils|亙剛wlbYSRV]diihkruspic]UMHINU\bhmprssqkheeedb_`[QC# ;G=>BEEDCEJMLNUZXaoyqmq|悿ǎぎ妇骄烤窘懂В览纮秓WQfz厓~倛帗枒i\`fgda_`bba_\YVV]g^-

'2BVeefhhiiims{們儊{qg]SJC??CCA@E@>;:9659BMW]chmprsssqmigffda^`WF1  9J@?BDEEDDEHJLQVUUY_afhmpnp{嫋煫狈还捣爆ア懒簥<E68792>砯^`q|~xsppu|們}rc\`egc_]\]]\ZXVVW[`O
  %*/A\ddgiiiknt{倓厖亃rk`XQKFB=534466=AEKQXafjmptwxwvtrnjhggea^[N1  2HB@BDDEEDEEGILPQNNSY[VNPX[]eqv€崟攺媶~剦籍导<E7B18D>ohpvsnifegjmlid_\_egea][ZYXWVVVWVT?
  #("&=Wchiijlpv|倓噳墖儅sjaYQLMNQSU\^]_adfimoqtx|~~|zwspljige_ZN1 
/GDABCDDDDEEEFHJLLLLMNMLOSX[_ehjkje`^_`elrz啗<7A>笢tykmolgda_]]]]]\ZXY_ee`\YWWVUTUVVNI5

  "*9Tfkjjmqx}亙厜寧帋寛億zutx{亜儐厔唶厒亐€€亜厖儉}zurmkjhcXM5  .FEBBCDDDDDEEEFGHIIHHHILQVZ\]\WSQRUZ]^`dknbgq啒<71>{{mklifca^ZWUTUURPPV_c_[WVUTTTUVUJE3
   
 .# 7Wgkjmry倓噴帒摃枛晸敂敁挆潥搹敆棔拹帊崒寣妵<E5AFA3>{wsnkjf^L6
,EFCBCDDDDDDDEEEGGHHIKNQVXZZYXWVUUWWXY\bgkaegjlx~|ynlkigda^ZURPONLJJOX]]XUTSRSTVWVMF3
 
 /& ;\ijlrz€剢墝彄棜潫灉洓殬槢潥晵摃晻晹敂搾憦崐厑|xsnjg_Q7 
 'AFDCDDDCDDCEEEFGGIJLORTVVUTSSRRQQRSTW[_dgmmljiovxvolkigea]YUQNLKHFFKSXYVTRQQRTWXYSK5
   /) F`hlrz亝垔崘敇潬ⅱ<E6BDAC>煘灊湚棔敁敂敃枟棖晹拸媶亅vqkg_O8 

!=FFEDDDDDCECEEFGHILNQRSSRRPPPPPPPQSUXZ]`arqpooqttromkjhe`\YTQMKJHFFKQUWURQOOPTWZ[YP8
  /+ 'H^ipx厜寧悡棞煝煘潧櫁枖敁摀敂晼棗棖敀悑<E69580>yrle^P8 
9FHGFEDDCECEDFFGIJLNPQQPPPPOOPPPQRTVXY[]^rqponopppnlljgc_[WTPMKIHFHMRUUTQOMLOTX[]^T= 
//
 &F]hpx€噷帎挄櫆潩湙棔敁拺憫憫憭挀摂敃敀憥垈{tld\P:
 5FIJHEDDDCECFEGGIJLNOOPPPPOPPPQQRTUVXY[\]pponmmmmmlkjhe`\YVSPNLJHHKPTUUSPNKJLSY]]`UD .3! $G`inv€垘悜挃枟枖憪悘弾帊崓帍弿悘悙憪悗妱{tld\O9  3FJLIFEDCDCEDFFHHJLMNNOOOOPPPQRRSTUXYZ\\]nmmlkkjjjihgea\YWUSQOLKJKMRUVUSPLIGIRY]\_SG +7( &B^djr}噷帍彁悘帊寣寢妷垐墛媽媻墛妺媼墑|rjb\Q8 4EIMJFEDDCDDEEGGIJKMMNNPOPPPQQRSTUVXY[\]]kkkjiihggfec`]YWVUSRPNMLMPSUWVTPKGEFPY][\PH '80  IYago{厞妸妺妸妷垏厔儌們剠厔儍剟厗厒{qg^VP<
4EHMJGEDCDDEEFFHHJKLNLONPOPQQRRTTVVXZ[]]^iiihggfeecb`][YWVUTSPONNNQTVWVTPKFCCMX]Z[OJ(  !64"  *BT_fox€儌儍剟剝儊}||{z{{{{|}~~{vndYPI9
5FHLJFECDDDEFFGGIIJMLOMPNPPRRRTTUVWYZ\]^^gffffeedcb`_][YWWUTSQPPPPRTUVWUQLGBAKV\ZYOK7 16( ";MX`iptvvvxxy{{zywvtrrrqrswxxxvrld\SI=2 7GGJIFDCCCEEEGGHHJKJNLPNQPRQRSTTUVXYZ\]^^eeeeeddcba`^][YXWUUTRRPQQRSUVVURMHCAJTZYWPLC$ 
+5-  1AOZbfhijjklnqrrokfcdfikmmmmmjd[SKB6':FEHGECCCDDDFEGGIJJMKPLQNRQRRSSUUVWYZ\]^^ccccccbcaa_^][ZYWWUTTRSPSRSTUUTRNJECIRWXVQLF/ &30

'7FNSX[\\]^_``_]YTQPTY]]ZYYYVQJA7+=DCEECCCCDEFEGGHIILKOLQNROSQSSTTUVWXY[\]^bbbbcac_b_`]^[[YYWVUTTQTPSSSUTTSOKGDHOUVURMF6
 !03!  -6<BHKJKKKJIHHFD@?AEGFFGEA=;7,  )@A@BBBBCCDEDGFHHIKJMKPMRNSPTRTTUTVVXXZ[[\```a`b_c]b]`[]Z[XYWVURUPURSUSUTSPMIFHMQTTROI>%.4$  !)/24555565445530/023431/-(   7A??@AABCCEDGEHHIJIMJOLQNSOUQTSTTUUVVWXYYY____`^a\b[a[`Z]Y[WXVTVQVQTTRURSRPNKIILOQRRPLD1  )4(  !$%&&%%$%&&%$##$$$" 0?@==?@ABCEDGEHGHIILJOKQNROUOURTTUUUUVVWWWW]^]^]_\a[bZ`Z_Z[YYXWWTWQURSTQTRRQNLKJLNPQQPLF9*  "1+ 

)9?=;<=?ABCDFEHGHIILIOJPMQNTOUQTSTTTUUUUVVVV\\][^[_[`Z`[_[\[YZXXUWRWRTTRUQSRPPNLLMNPPQPMH?5# *+

#3;;9:;=?ABCEEGGHIIKIMJQKRNSOUPTRTTTUTTVUUUUU[\Y]Y]Y_Z_[^[]\Z\YYWXTYQUSSTQSRQQOONNNOOPQPNJD=1
!("


$278778:=?ACDEGGIIIKIMJOJRMSNUOTRTTTTUTVSUUUUUZX\W]W]Y^[][][[\Y[XYWYRYRUTRTRQTOROPNPNPPQQPMHD=* #$ )4754568:=?ACEFGHIIKIMJNKQLSMUOURTTSTTUURWRWRVTX[W\U]V]Y[[[][\[[Y[XYUYRWSUTTQTPTORNRNRORRRRPMIG;# " -78412358:=@BDEGHIJLINJNKPLRMSOUQTSSTTTTTWRXPYQVYVZU]S]V\ZZ][[[[[[ZZXYUZRXRURURSQSPSNTNSPRRSRPMLF5 
 ".673//0358:>ACEGHIJKKMJOKPLRMROSQTRTTTTTUTTURYOWSVYU[Q^S]W[[Y\[[[Z[ZYYXYUYSWSUSSTRRRPTNUNTRSTTSPMJB3  
'1452/-.0368<?BDGHJKKLMKOKQKRMSOSQTRSTTTTTTTTUTRWRUWUXS^O^S\XZ[Z[[[\Z\ZYYXYUYTVTSUQUQSSPUNVOTRTTUSOLH?*
  &3430-,,.136:=@CFHJKMMNLOMPLRMSOSQSRTSTTURUUTTTTTSTTUXTZO^Q\U[YZZ[[[Z\Z[ZZYXYUXUUWRXPVRSTQVNVQTTTUUQMJD5 
 #-20.,+,,/247;>BEHJLMMNNPNONPNSOSQSRTSTTTSUSSUSTTTRTSWTXR]O\S\U\X[Z[[[Z[[ZYZXWYVWWSYQXRVTSUPXOURTTTUSOKH?,   
"(,,,***+./259=@DFILMNONPNPOPOROSPSRSSUSUTURTTSSTRTRRTTWSYO]Q[S]U]X\Z[[[[[Z[XZYWYWUYSZRXTUUSWPWPTRRSTTQNLH;+  

 $%'))))*+,.147;>BEHKLNOOQNQPPPQPSPSRSSURWRUSTTRSSRSQTRRVSWR[O\Q]Q^T]W[YZZ[Z[W[XXYXXXUYSZSXUUWRYQVRSRRRRRONLE8* 
  "$%%&'(()*,-036:=ACFIKMNOPORPPQPQRPTRTSURWQVRTSSSSQRRRQRQTWSXP\N^O`P_S]W[YZYZXZXYYWYWYYVZUZUYWUYRWRSRQPQQQPNMIA6)    "$$$$%&'')+-/269<@BEGIJMNOOQNQPPQRPTRTSURWQWRURSRRRQRPRQQRUTVRYN]M_N_Q]T[WYXYXYWXWWYWYWYYWZVYWVYSYSUSRPOOPPPONLF?7.
  "####$$%'(*-/159<?ACEFHJLMNOOPOPPQPTQUSUTVRWRUSSRRQRQPSORQPUTSWQZO\O]Q\TZWYXXXWWVVVWVXWYXYXYYYWZT[SWTSRPONNOOPPNLHB>8+  
 !"######%'),/269=?ACDEFGIJLLMNNPOQPSQVRUTUTVSUSSRRRRORQORPOQTUURWQYQZRZTYWXWXWVWUVUUUVVXWZXZX[W\U]SYUUTRPNNNNOPPPPNLID>3" 
 !!"""""##%(+/26:<?ABCDEFGHIJJLMNNPNRPTRVTVUTTUSTRTQROSNQPPORNRUUURWRWSXUWWWWWWWWUVSTTTUVWYW[W\V]U]U[VWUTRPNMMNOPPQQQQOLHD=2$  
 !!!""""#%).26:<?ABCDDEFFGHIJKLLNNPPRRUTVUVVTTTRTPSPRNROPPQMQVSSTTSUTVUWWWWWWWWUUTTSTTUVWWZX[X\X[WZWXWUURPNMLNOPPQRRRQNKIGD=4/*()+,+&   !!!""""#%*048;>@ABCDDEEGGHHIJKLMNOPQSTUUVUVUTSTRSQRPQOPOPNQO

243
examples/img/sh1r.pgm Normal file

File diff suppressed because one or more lines are too long

2313
examples/img/tetris.h Normal file

File diff suppressed because it is too large Load diff

232
examples/jawbreaker.cpp Normal file
View file

@ -0,0 +1,232 @@
/*
#
# File : jawbreaker.cpp
# ( C++ source file )
#
# Description : A funny game featuring small colored balls.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Main procedure
//----------------
int main(int argc, char **argv) {
// Display help (if option '-h' or '--help' specified) and retrieve program arguments
cimg_usage("A small and funny game featuring colored balls.\n (by David Tschumperlé).");
const char *score_file = cimg_option("-s",(char*)0,"Specify score file to use (0=default file).");
cimg_help("\n"
"** Quick Help *********************************************************\n\n"
"Goal : Delete the board by clicking on groups of adjacent colored balls\n"
" (a group is made of at least two balls with the same color).\n"
" Suppressing large sets gives higher scores.\n\n"
"In-game keys : - BACKSPACE or SPACE = Undo last move\n"
" - CTRL+F = Toggle fullscreen mode\n"
" - ESC = Quit application\n"
" - Q = End current game\n\n"
"*********************************************************************");
// Load score file if available
CImgList<unsigned int> score_history;
char filename_history[1024];
std::sprintf(filename_history,"%s%s",score_file?"":cimg::temporary_path(),score_file?score_file:"/jawbreaker.score");
std::FILE *file = std::fopen(filename_history,"r");
if (file) { std::fclose(file); score_history = CImg<unsigned int>::get_load_dlm(filename_history)<'y'; }
// Create ball graphics
const unsigned int W = 12, H = 14, Wi = (W<<5), Hi = (H<<5);
unsigned int score = 0, previous_score = 0, shape_score = 0,
best_score = score_history?score_history.max():0U;
const CImg<> colors(3,7,1,1, 255,255,255, 205,0,230, 0,235,0, 235,255,0, 235,0,0, 0,128,255, 450,350,300);
const unsigned char
white[] = { 255,255,255 }, orange[] = { 255,128,64 }, yellow[] = { 255,255,64 }, red[] = { 255,64,64 }, six = 6;
CImgList<> balls0(7,32,32,1,3,0);
cimglist_for(balls0,l) if (l) {
balls0[l].draw_circle(16,16,14,colors.data(0,l));
cimg_forXYC(balls0[l],x,y,k) if (balls0(l,x,y,k)) (balls0(l,x,y,k)*=(32 - x + y)/60.0f)+=20;
balls0[l].draw_circle(16,16,14,colors.data(0,l),0.5f,~0U).
draw_circle(20,10,5,colors.data(),0.2f).draw_circle(22,8,2,colors.data(),0.4f).cut(0,255);
}
// Create background graphics
CImgList<unsigned char> balls(balls0);
CImg<unsigned char>
mask = balls[1].get_cut(0,1).channel(0).dilate(3),
background = CImg<unsigned char>(Wi,Hi,1,3,0).
noise(255,1).blur(6,20,0,true).equalize(100,0,255).blur(2,4,0,true);
background.get_shared_channel(0)/=4; background.get_shared_channel(1)/=8; background.get_shared_channel(2)/=2;
// Begin user-interaction loop.
CImg<unsigned char> board, previous_board, selected_board, shape, img(background);
CImgDisplay disp(img.width(),img.height(),"Jawbreaker",0);
bool redraw = true, gameover = false, title = true;
for (float opac = 0.0f; !disp.is_closed(); ) {
// Init board
if (!board) {
(++((board.assign(W,H,1,1,5).noise(5,1))%=5)).get_shared_row(0).fill(0);
opac = (float)(score = previous_score = shape_score = 0);
gameover = false; redraw = title = true;
previous_board = board;
}
// Draw graphical board
if (redraw) {
(img=background).draw_text(2,2,"Score : %u",yellow,0,0.7f,24,score).
draw_text(Wi - 90,2,"Best : %u",orange,0,0.9f,17,best_score);
if (selected_board) {
cimg_forXY(selected_board,x,y) if (selected_board(x,y))
img.draw_image(x<<5,y<<5,balls[selected_board(x,y)],mask);
} else cimg_forXY(board,x,y) if (board(x,y)) img.draw_image(x<<5,y<<5,balls[board(x,y)],mask);
if (title) {
CImg<unsigned char> text1, text2;
text1.draw_text(0,0,"- Jawbreaker -",white,0,1,48).resize(-100,-100,1,3);
text2.draw_text(0,0,"Press button to start",yellow,0,1,24).resize(-100,-100,1,3);
(img/=2).draw_image((Wi - text1.width())/2,
(Hi - text1.height())/2,
text1,text1.get_dilate(7),1,255).
draw_image((Wi - text2.width())/2,
(Hi + text1.height() + 10)/2,
text2,text2.get_dilate(5),0.7f,255);
for (float i = 1; i<10 && !disp.is_keyESC(); i+=0.25)
disp.display(img.get_crop((int)(Wi*(0.5f - i*i/200.0f)),(int)(Hi*(0.5f - i*i*i*i/20000.0f)),
(int)(Wi*(0.5f + i*i/200.0f)),(int)(Hi*(0.5f + i*i*i*i/20000.0f)))).wait(20);
}
}
if ((opac-=0.06f)>0) disp.display((+img).draw_text(disp.mouse_x() - 8,disp.mouse_y() - 80 + (int)(60*opac),"+%u",
white,0,(float)std::sqrt(opac),32,shape_score)).wait(20);
else { if (redraw) { disp.display(img); redraw = false; } else disp.wait(); }
// Handle key and window events
if (disp.is_resized()) disp.resize(disp);
if (disp.is_keyBACKSPACE() || disp.is_keySPACE()) {
board = previous_board; score = previous_score; selected_board.assign(); redraw = true; disp.set_key();
}
if (disp.is_keyQ()) { gameover = true; disp.set_key(); }
if (disp.is_keyESC()) disp.close();
if (disp.is_keyCTRLLEFT() && disp.is_keyF()) disp.toggle_fullscreen().display(img);
// Handle ball selection and removal
const int x = disp.mouse_x()*board.width()/disp.width(), y = disp.mouse_y()*board.height()/disp.height();
if (disp.button()&1 && x>=0 && y>=0) {
if (title) { title = false; redraw = true; } else {
if (!board(x,y)) { selected_board.assign(); redraw = true; }
else {
if (!selected_board || selected_board(x,y)!=6) {
(selected_board=board).draw_fill(x,y,0,&six,1,shape);
if ((shape_score=(unsigned int)shape.sum())<2) selected_board.assign();
else { shape_score-=1; shape_score*=shape_score; opac = 1.0f; redraw = true; }
} else {
selected_board.assign();
previous_board = board;
previous_score = score;
score += shape_score;
board&=--shape;
redraw = true;
// Handle board modification due to ball removal
for (int pmax = board.width(), p = 0; p<pmax; ++p) {
for (int q = board.height() - 1, qs = q; q>=0; --q) {
while (qs>=0 && !board(p,qs)) --qs;
board(p,q) = (qs>=0?board(p,qs--):0);
}
if (!board(p,board.height() - 1)) {
board.draw_image(p,board.get_crop(p,0,board.width() - 1,board.height() - 1).shift(-1));
if (p<pmax) { p--; pmax--; }
}
}
// Test possible end of the game
gameover = true;
cimg_forXY(board,p,q)
if (board(p,q) && ((q && board(p,q)==board(p,q - 1)) || (p && board(p,q)==board(p - 1,q))))
gameover = false;
}
}
}
disp.set_button();
}
// If game is over...
if (gameover && opac<=0) {
CImg<unsigned char> text1, text2, text3, text4, text5, text6;
text1.draw_text(0,0,"Game Over !",white,0,1,48).resize(-100,-100,1,3);
const unsigned int remaining_balls = (unsigned int)board.get_cut(0,1).sum();
if (remaining_balls<8) {
const unsigned int bonus = (22 - 2*remaining_balls)*10;
score += bonus;
text2.draw_text(0,0,"Jawbreaker Bonus : +%u",white,0,1,24,bonus);
}
score_history.insert(CImg<unsigned int>::vector(score));
text3.draw_text(0,0,"Final score : %u",yellow,0,1,24,score).resize(-100,-100,1,3);
text4.draw_text(0,0,score>best_score?"** New record ! **":"Best score : %u",
orange,0,1,24,score>best_score?score:best_score).resize(-100,-100,1,3);
text5.draw_text(0,0,"Average score : %u",red,0,1,24,
score_history?(unsigned int)(score_history>'x').mean():0U).resize(-100,-100,1,3);
text6.draw_text(0,0,"Games played : %u",red,0,1,24,score_history.size()).resize(-100,-100,1,3);
if (score>best_score) best_score = score;
unsigned int yt = (Hi - text1.height())/2 - 20;
(img/=2).draw_image((Wi - text1.width())/2,yt,text1,text1.get_dilate(7),1,255); yt+=80;
if (text2) { img.draw_image((Wi - text2.width())/2,yt,text2,text2.get_dilate(5),1,255); yt+=25; }
img.draw_image((Wi - text3.width())/2,yt,text3,text3.get_dilate(5),1,255).
draw_image((Wi - text4.width())/2,yt + 25,text4,text4.get_dilate(5),1,255).
draw_image((Wi - text5.width())/2,yt + 50,text5,text5.get_dilate(5),1,255).
draw_image((Wi - text6.width())/2,yt + 75,text6,text6.get_dilate(5),1,255).display(disp);
for (disp.flush(); !disp.is_closed() && !disp.key() && !disp.button(); disp.wait())
if (disp.is_resized()) disp.resize(disp);
disp.flush();
board.assign();
for (float i = 10; i>0 && !disp.is_keyESC(); i-=0.25)
disp.display(img.get_crop((int)(Wi*(0.5f - i*i*i*i/20000.0f)),(int)(Hi*(0.5f - i*i/200.0f)),
(int)(Wi*(0.5f + i*i*i*i/20000.0f)),(int)(Hi*(0.5f + i*i/200.0f)))).wait(20);
}
}
// Save score history if possible, and exit.
if (score_history) {
file = std::fopen(filename_history,"w");
if (file) { std::fclose(file); (score_history>'y').save_dlm(filename_history); }
}
return 0;
}

View file

@ -0,0 +1,120 @@
/*
#
# File : mcf_levelsets2d.cpp
# ( C++ source file )
#
# Description : Implementation of the Mean Curvature Flow on a 2D curve,
# using the framework of Level Sets.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Retrieve the curve corresponding to the zero level set of the distance function.
template<typename T>
CImg<unsigned char> get_level0(const CImg<T>& img) {
CImg<unsigned char> dest(img);
CImg_2x2(I,T); Inn = 0;
cimg_for2x2(img,x,y,0,0,I,T) if (Icc*Inc<0 || Icc*Icn<0) dest(x,y) = 255; else dest(x,y) = Icc<0?100:0;
return dest;
}
/*--------------------
Main procedure
----------------------*/
int main(int argc,char **argv) {
cimg_usage("Perform a Mean Curvature Flow on closed curves, using Level Sets");
const float dt = cimg_option("-dt",0.8f,"PDE time step");
const unsigned int nb_iterations = cimg_option("-iter",10000,"Number of iterations");
// Create a user-defined closed curve.
CImg<unsigned char> curve(256,256,1,2,0);
unsigned char col1[] = {0,255}, col2[] = {200,255}, col3[] = {255,255};
curve.draw_grid(20,20,0,0,false,false,col1,0.4f,0xCCCCCCCC,0xCCCCCCCC).
draw_text(5,5,"Please draw your curve\nin this window\n(Use your mouse)",col1);
CImgDisplay disp(curve,"Mean curvature flow",0);
int xo = -1, yo = -1, x0 = -1, y0 = -1, x1 = -1, y1 = -1;
while (!disp.is_closed() && (x0<0 || disp.button())) {
if (disp.button() && disp.mouse_x()>=0 && disp.mouse_y()>=0) {
if (x0<0) { xo = x0 = disp.mouse_x(); yo = y0 = disp.mouse_y(); } else {
x1 = disp.mouse_x(); y1 = disp.mouse_y();
curve.draw_line(x0,y0,x1,y1,col2).display(disp);
x0 = x1; y0 = y1;
}
}
disp.wait();
if (disp.is_resized()) disp.resize(disp);
}
curve.draw_line(x1,y1,xo,yo,col2).channel(0).draw_fill(0,0,col3);
CImg<> img = CImg<>(curve.get_shared_channel(0)).normalize(-1,1);
// Perform the "Mean Curvature Flow".
img.distance_eikonal(10);
CImg_3x3(I,float);
for (unsigned int iteration = 0; iteration<nb_iterations && !disp.is_closed() &&
!disp.is_keyQ() && !disp.is_keyESC(); ++iteration) {
CImg<float> velocity(img.width(),img.height(),img.depth(),img.spectrum());
float *ptrd = velocity.data(), veloc_max = 0;
cimg_for3x3(img,x,y,0,0,I,float) {
const float
ix = (Inc - Ipc)/2,
iy = (Icn - Icp)/2,
ixx = Inc + Ipc - 2*Icc,
iyy = Icn + Icp - 2*Icc,
ixy = (Ipp + Inn - Inp - Ipn)/4,
ngrad = ix*ix + iy*iy,
iee = (ngrad>1e-5)?((iy*iy*ixx - 2*ix*iy*ixy + ix*ix*iyy)/ngrad):0;
*(ptrd++) = iee;
if (iee>veloc_max) veloc_max = iee; else if (-iee>veloc_max) veloc_max = -iee;
}
if (veloc_max>0) img+=(velocity*=dt/veloc_max);
if (!(iteration%10)) {
get_level0(img).resize(disp.width(),disp.height()).
draw_grid(20,20,0,0,false,false,col3,0.4f,0xCCCCCCCC,0xCCCCCCCC).
draw_text(5,5,"Iteration %d",col3,0,1,13,iteration).display(disp);
}
if (!(iteration%60)) img.distance_eikonal(1,3);
if (disp.is_resized()) disp.resize();
}
return 0;
}

View file

@ -0,0 +1,180 @@
/*
#
# File : mcf_levelsets3d.cpp
# ( C++ source file )
#
# Description : Implementation of the Mean Curvature Flow on Surfaces
# using the framework of Level Sets 3D.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#undef min
#undef max
// Apply the Mean curvature flow PDE
//-----------------------------------
template<typename T> CImg<T>& mcf_PDE(CImg<T>& img, const unsigned int nb_iterations,
const float dt=0.25f, const float narrow=4.0f) {
CImg<float> velocity(img.width(),img.height(),img.depth(),img.spectrum());
CImg_3x3x3(I,float);
for (unsigned int iteration = 0; iteration<nb_iterations; ++iteration) {
float *ptrd = velocity.data(), veloc_max = 0;
cimg_for3x3x3(img,x,y,z,0,I,float) if (cimg::abs(Iccc)<narrow) {
const float
ix = (Incc - Ipcc)/2,
iy = (Icnc - Icpc)/2,
iz = (Iccn - Iccp)/2,
norm = (float)std::sqrt(1e-5f + ix*ix + iy*iy + iz*iz),
ixx = Incc + Ipcc - 2*Iccc,
ixy = (Ippc + Innc - Inpc - Ipnc)/4,
ixz = (Ipcp + Incn - Incp - Ipcn)/4,
iyy = Icnc + Icpc - 2*Iccc,
iyz = (Icpp + Icnn - Icnp - Icpn)/4,
izz = Iccn + Iccp - 2*Iccc,
a = ix/norm,
b = iy/norm,
c = iz/norm,
inn = a*a*ixx + b*b*iyy + c*c*izz + 2*a*b*ixy + 2*a*c*ixz + 2*b*c*iyz,
veloc = ixx + iyy + izz - inn;
*(ptrd++) = veloc;
if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc;
} else *(ptrd++) = 0;
if (veloc_max>0) img+=(velocity*=dt/veloc_max);
}
return img;
}
/*----------------------
Main procedure
--------------------*/
int main(int argc,char **argv) {
cimg_usage("Mean curvature flow of a surface, using 3D level sets");
const char *file_i = cimg_option("-i",(char*)0,"Input image");
const float dt = cimg_option("-dt",0.05f,"PDE Time step");
const float narrow = cimg_option("-band",5.0f,"Size of the narrow band");
const bool both = cimg_option("-both",false,"Show both evolving and initial surface");
// Define the signed distance map of the initial surface.
CImg<> img;
if (file_i) {
const float sigma = cimg_option("-sigma",1.2f,"Segmentation regularity");
const float alpha = cimg_option("-alpha",5.0f,"Region growing tolerance");
img.load(file_i).channel(0);
CImg<int> s;
CImgDisplay disp(img,"Please select a starting point");
while (!s || s[0]<0) s = img.get_select(0,disp);
CImg<> region;
float tmp[] = { 0 };
img.draw_fill(s[0],s[1],s[2],tmp,1,region,alpha);
((img = region.normalize(-1,1))*=-1).blur(sigma);
}
else { // Create synthetic implicit function
img.assign(60,60,60);
const float exte[] = { 1 }, inte[] = { -1 };
img.fill(*exte).draw_rectangle(15,15,15,45,45,45,inte).draw_rectangle(25,25,0,35,35,img.depth() - 1,exte).
draw_rectangle(0,25,25,img.width() - 1,35,35,exte).draw_rectangle(25,0,25,35,img.height() - 1,35,exte).noise(0.7);
}
img.distance_eikonal(10,0,0.1f);
// Compute corresponding surface triangularization by the marching cube algorithm (isovalue 0).
CImg<> points0;
CImgList<unsigned int> faces0;
if (both) points0 = img.get_isosurface3d(faces0,0);
const CImgList<unsigned char> colors0(faces0.size(),CImg<unsigned char>::vector(100,200,255));
const CImgList<> opacities0(faces0.size(),1,1,1,1,0.2f);
// Perform MCF evolution.
CImgDisplay disp(256,256,0,1), disp3d(512,512,0,0);
float alpha = 0, beta = 0;
for (unsigned int iteration = 0; !disp.is_closed() && !disp3d.is_closed() &&
!disp.is_keyESC() && !disp3d.is_keyESC() && !disp.is_keyQ() && !disp3d.is_keyQ(); ++iteration) {
disp.set_title("3D implicit Function (iter. %u)",iteration);
disp3d.set_title("Mean curvature flow 3D - Isosurface (iter. %u)",iteration);
// Apply PDE on the distance function.
mcf_PDE(img,1,dt,narrow); // Do one iteration of mean curvature flow
// Every 10 steps, do one iteration of distance function re-initialization.
if (!(iteration%10)) img.distance_eikonal(1,narrow,0.5f);
// Compute surface triangularization by the marching cube algorithm (isovalue 0)
CImgList<unsigned int> faces;
CImg<> points = img.get_isosurface3d(faces,0);
CImgList<unsigned char> colors(faces.size(),CImg<unsigned char>::vector(200,128,100));
CImgList<> opacities(faces.size(),CImg<>::vector(1.0f));
const float fact = 3*std::max(disp3d.width(),disp3d.height())/(4.0f*std::max(img.width(),img.height()));
// Append initial object if necessary.
if (both) {
points.append_object3d(faces,points0,faces0);
colors.insert(colors0);
opacities.insert(opacities0);
}
// Center and rescale the objects
cimg_forX(points,l) {
points(l,0)=(points(l,0) - img.width()/2)*fact;
points(l,1)=(points(l,1) - img.height()/2)*fact;
points(l,2)=(points(l,2) - img.depth()/2)*fact;
}
// Display 3D object on the display window.
CImg<unsigned char> visu(disp3d.width(),disp3d.height(),1,3,0);
const CImg<> rot = CImg<>::rotation_matrix(1,0,0,(beta+=0.5f))*CImg<>::rotation_matrix(0,1,1,(alpha+=3));
if (points.size()) {
visu.draw_object3d(visu.width()/2.0f,visu.height()/2.0f,0.0f,
rot*points,faces,colors,opacities,3,
false,500.0,0.0f,0.0f,-8000.0f).display(disp3d);
} else visu.fill(0).display(disp3d);
img.display(disp.wait(20));
if ((disp3d.button() || disp3d.key()) && points.size() && !disp3d.is_keyESC() && !disp3d.is_keyQ()) {
const unsigned char white[3] = { 255, 255, 255 };
visu.fill(0).draw_text(10,10,"Time stopped, press any key to start again",white).
display_object3d(disp3d,points,faces,colors,opacities,true,4,3,false,500,0,0,-5000,0.4f,0.3f);
disp3d.set_key();
}
if (disp.is_resized()) disp.resize(false);
if (disp3d.is_resized()) disp3d.resize(false);
disp.wait(50);
}
return 0;
}

229
examples/odykill.cpp Normal file
View file

@ -0,0 +1,229 @@
/*
#
# File : odykill.cpp
# ( C++ source file )
#
# Description : Simple shoot-em-up game featuring the Robotvis/Odyssee Team !
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "img/odykill.h"
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main(int argc,char **argv) {
// Create game graphics
CImg<unsigned char> graphics[21] = {
CImg<unsigned char>(data_tomato,100,100,1,3,false),
CImg<unsigned char>(data_heart,100,100,1,3,false),
CImg<unsigned char>(data_dynamite,100,100,1,3,false),
CImg<unsigned char>(data_brain,100,100,1,3,false),
CImg<unsigned char>(data_cdrom,100,100,1,3,false),
CImg<unsigned char>(data_enemy,113,150,1,3,false),
CImg<unsigned char>(data_enemy2,116,155,1,3,false),
CImg<unsigned char>(data_enemy3,104,134,1,3,false),
CImg<unsigned char>(data_enemy4,141,151,1,3,false),
CImg<unsigned char>(data_enemy5,140,152,1,3,false),
CImg<unsigned char>(data_enemy6,131,156,1,3,false),
CImg<unsigned char>(data_enemy7,114,125,1,3,false),
CImg<unsigned char>(data_enemy8,97,125,1,3,false),
CImg<unsigned char>(data_enemy9,143,134,1,3,false),
CImg<unsigned char>(data_enemy10,158,214,1,3,false),
CImg<unsigned char>(data_enemy11,131,168,1,3,false),
CImg<unsigned char>(data_enemy12,114,138,1,3,false),
CImg<unsigned char>(data_enemy13,144,144,1,3,false),
CImg<unsigned char>(data_enemy14,132,153,1,3,false),
CImg<unsigned char>(data_enemy15,152,151,1,3,false),
CImg<unsigned char>(data_enemy16,139,185,1,3,false),
};
CImg<> masks[21];
const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 };
// Display weapon selection menu
CImg<unsigned char> back0(640,480,1,3), title(data_title,294,94,1,3,true), choose(data_choose,524,49,1,3,true);
back0.fill(0).draw_image(back0.width()/2 - title.width()/2,30,title).
draw_image(back0.width()/2 - choose.width()/2,150,choose);
CImgDisplay disp(back0,"OdyKill");
int weapon=-1;
while (!disp.is_closed() && !disp.button()) {
weapon = -1;
for (int k=0; k<5; k++) {
const int mx = disp.mouse_x(), my = disp.mouse_y();
if (!((mx - 40)/110==k && my>250 && my<350)) back0.draw_image(40 + k*110,250,graphics[k]/2.0);
else back0.draw_image(40 + k*110,250,graphics[weapon=k]);
}
CImg<unsigned char> tmp = CImg<unsigned char>().draw_text(0,0,
weapon==0?" Tomato ":
weapon==1?" Heart ":
weapon==2?" Dynamite ":
weapon==3?" Brain ":
weapon==4?" CD-Rom ":
" ",white,black,1,32).resize(-100,-100,1,1),
tmp2 = tmp.get_blur(6).normalize(0,255).draw_image(tmp,0.5f);
cimg_forC(back0,k) back0.draw_image(250,390,0,k,tmp2);
disp.resize(disp).display(back0).wait();
if (disp.is_keyCTRLLEFT() && disp.is_keyF()) disp.toggle_fullscreen();
if (disp.is_closed() || disp.is_keyQ() || disp.is_keyESC()) std::exit(0);
}
disp.hide_mouse();
/*---------------------------------
Go !
--------------------------------*/
const CImg<unsigned char>
background = CImg<unsigned char>(100,100,1,3,0).noise(100,2).draw_plasma().
resize(back0.width(),back0.height(),1,3,5)/2.5;
for (unsigned int k = 0; k<21; k++) {
CImg<> tmp = graphics[k].resize(k<5?32:164,k<5?32:164,1,3);
cimg_forXY(tmp,x,y) tmp(x,y) = (tmp(x,y,0)==255 && tmp(x,y,1)==255 && tmp(x,y,2)==255)?0.0f:1.0f;
masks[k] = tmp.get_channel(0);
graphics[k].resize(k<5?32:164,k<5?32:164,1,3,5);
}
CImg<unsigned char> canvas(background);
int n = 5 + ((int)(200*cimg::rand())%16);
CImg<unsigned char> tomato = graphics[weapon], enemy = graphics[n];
CImg<> m_tomato = masks[weapon], m_enemy = masks[n];
double angle = 0;
int tomato_x = 0,tomato_y = 0,shooted = 0;
double enemy_x = -1000, enemy_y = -1000, enemy_z = -1000, tomato_z = 0, vx = 0, vy = 0, vz = 0, va = 0;
double speed = cimg_option("-speed",5.0,"Speed");
int timeleft = 2000, score = 0;
CImg<unsigned char> r_enemy;
// Main loop
while (timeleft && !disp.is_closed() && !disp.is_keyESC() && !disp.is_keyQ()) {
--timeleft;
const int mx = disp.mouse_x()*back0.width()/disp.width(), my = disp.mouse_y()*back0.height()/disp.height();
// Handle object motion
if (tomato_z>0) {
tomato_z+=0.07; tomato_y -= (int)(20*std::cos(cimg::PI/7 + tomato_z*cimg::PI));
if (tomato_z>=1) { tomato_z=0; tomato_x = mx; tomato_y = my; }
}
if (!shooted) { enemy_x +=vx; enemy_y +=vy; enemy_z +=vz; }
else {
va = 10;
enemy_y += vy;
vy += 2;
tomato_z = 0;
if (enemy_y>5*canvas.height()/4) {
shooted = 0;
int nn = 5 + ((int)(200*cimg::rand())%16);
enemy = graphics[nn];
m_enemy = masks[nn];
enemy_x=cimg::rand(-1,1)*1e8; enemy_y=cimg::rand(-1,1)*1e8; enemy_z=cimg::rand(-1,1)*1e8;
va = angle = 0;
}
}
if (enemy_x<0) { enemy_x=0; vx = speed*cimg::rand(-1,1); }
if (enemy_x>canvas.width()) { enemy_x=canvas.width(); vx = speed*cimg::rand(-1,1); }
if (enemy_y<0) { enemy_y=0; vy = speed*cimg::rand(-1,1); }
if (!shooted && enemy_y>canvas.height()) { enemy_y=canvas.height(); vy = speed*cimg::rand(-1,1); }
if (enemy_z<0.1) { enemy_z = 0.1; vz = speed*0.01*cimg::rand(-1,1); }
if (enemy_z>0.7) { enemy_z = 0.7; vz = speed*0.01*cimg::rand(-1,1); }
angle+=va;
// Handle mouse interaction
if (!disp.button()) {
if (tomato_z==0) {
tomato_x = mx; tomato_y = my;
}
} else tomato_z +=0.0001;
// Detect shooting
if (cimg::abs(tomato_z - enemy_z)<0.1) {
if (tomato_x>enemy_x - r_enemy.width()/2 && tomato_x<enemy_x + r_enemy.width()/2 &&
tomato_y>enemy_y - r_enemy.height()/2 && tomato_y<enemy_y + r_enemy.height()/2) {
score++;
shooted = 1;
}
}
// Draw into canvas
canvas = background;
r_enemy = enemy.get_resize((int)(8 + enemy.width()*(1 - enemy_z)),
(int)(8 + enemy.height()*(1 - enemy_z)),-100,-100);
CImg<> rm_enemy = m_enemy.get_resize(r_enemy.width(),r_enemy.height());
CImg<unsigned char> r_tomato = tomato.get_resize((int)(8 + tomato.width()*(1 - tomato_z)),
(int)(8 + tomato.height()*(1 - tomato_z)),-100,-100);
CImg<> rm_tomato = m_tomato.get_resize(r_tomato.width(),r_tomato.height());
if (angle!=0) {
r_enemy.rotate((float)angle,0,0);
rm_enemy.rotate((float)angle,0,0);
cimg_forXY(r_enemy,x,y) r_enemy(x,y,0) = (r_enemy(x,y,0) + 255)/2;
}
r_enemy*=(1 - (enemy_z - 0.1)/1.6);
r_tomato*=(1 - tomato_z/1.6);
rm_enemy*=(1 - (enemy_z - 0.1)/1.6);
if (enemy_z>tomato_z) {
canvas.draw_image((int)(enemy_x - r_enemy.width()/2),
(int)(enemy_y - r_enemy.height()/2),
r_enemy,rm_enemy);
if (tomato_x>=0) canvas.draw_image(tomato_x - r_tomato.width()/2,
tomato_y - r_tomato.height()/2,
r_tomato,rm_tomato);
}
else {
if (tomato_x>=0) canvas.draw_image(tomato_x - r_tomato.width()/2,
tomato_y - r_tomato.height()/2,
r_tomato,rm_tomato);
canvas.draw_image((int)(enemy_x - r_enemy.width()/2),
(int)(enemy_y - r_enemy.height()/2),
r_enemy,rm_enemy);
}
canvas.draw_text(1,1," Time left %d, Score = %d",white,0,0.5f,24,timeleft,score);
disp.resize(disp).display(canvas).wait(25);
if (disp.is_keyCTRLLEFT() && disp.is_keyF()) disp.toggle_fullscreen();
}
std::fprintf(stderr,"\n\n YOUR SCORE : %d\n\n\n",score);
return 0;
}

View file

@ -0,0 +1,231 @@
/*
#
# File : pde_TschumperleDeriche2d.cpp
# ( C++ source file )
#
# Description : Implementation of the Tschumperlé-Deriche's Regularization
# PDE, for 2D multivalued images, as described in the articles below.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# (1) PDE-Based Regularization of Multivalued Images and Applications.
# (D. Tschumperlé). PhD Thesis. University of Nice-Sophia Antipolis, December 2002.
# (2) Diffusion PDE's on Vector-valued Images : Local Approach and Geometric Viewpoint.
# (D. Tschumperlé and R. Deriche). IEEE Signal Processing Magazine, October 2002.
# (3) Vector-Valued Image Regularization with PDE's : A Common Framework for Different Applications.
# (D. Tschumperlé and R. Deriche). CVPR'2003, Computer Vision and Pattern Recognition,
# Madison, United States, June 2003.
#
# This code can be used to perform image restoration, inpainting, magnification or flow visualization.
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
#undef min
#undef max
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line arguments
//-----------------------------
cimg_usage("Tschumperlé-Deriche's flow for 2D Image Restoration, Inpainting, Magnification or Flow visualization");
const char *file_i = cimg_option("-i",cimg_imagepath "milla.bmp","Input image");
const char *file_m = cimg_option("-m",(char*)NULL,"Mask image (if Inpainting)");
const char *file_f = cimg_option("-f",(char*)NULL,"Flow image (if Flow visualization)");
const char *file_o = cimg_option("-o",(char*)NULL,"Output file");
const double zoom = cimg_option("-zoom",1.0,"Image magnification");
const unsigned int nb_iter = cimg_option("-iter",100000,"Number of iterations");
const double dt = cimg_option("-dt",20.0,"Adapting time step");
const double alpha = cimg_option("-alpha",0.0,"Gradient smoothing");
const double sigma = cimg_option("-sigma",0.5,"Structure tensor smoothing");
const float a1 = cimg_option("-a1",0.5f,"Diffusion limiter along minimal variations");
const float a2 = cimg_option("-a2",0.9f,"Diffusion limiter along maximal variations");
const double noiseg = cimg_option("-ng",0.0,"Add gauss noise before aplying the algorithm");
const double noiseu = cimg_option("-nu",0.0,"Add uniform noise before applying the algorithm");
const double noises = cimg_option("-ns",0.0,"Add salt&pepper noise before applying the algorithm");
const bool stflag = cimg_option("-stats",false,"Display image statistics at each iteration");
const unsigned int save = cimg_option("-save",0,"Iteration saving step");
const unsigned int visu = cimg_option("-visu",10,"Visualization step (0=no visualization)");
const unsigned int init = cimg_option("-init",3,"Inpainting initialization (0=black, 1=white, 2=noise, 3=unchanged)");
const unsigned int skip = cimg_option("-skip",1,"Step of image geometry computation");
bool view_t = cimg_option("-d",false,"View tensor directions (useful for debug)");
double xdt = 0;
// Variable initialization
//-------------------------
CImg<> img, flow;
CImg<int> mask;
if (file_i) {
img = CImg<>(file_i).resize(-100,-100,1,-100);
if (file_m) mask = CImg<unsigned char>(file_m).resize(img.width(),img.height(),1,1);
else if (zoom>1) {
mask = CImg<int>(img.width(),img.height(),1,1,-1).
resize((int)(img.width()*zoom),(int)(img.height()*zoom),1,1,4) + 1;
img.resize((int)(img.width()*zoom),(int)(img.height()*zoom),1,-100,3);
}
} else {
if (file_f) {
flow = CImg<>(file_f);
img = CImg<>((int)(flow.width()*zoom),(int)(flow.height()*zoom),1,1,0).noise(100,2);
flow.resize(img.width(),img.height(),1,2,3);
} else
throw CImgException("You need to specify at least one input image (option -i), or one flow image (option -f)");
}
img.noise(noiseg,0).noise(noiseu,1).noise(noises,2);
float initial_min, initial_max = img.max_min(initial_min);
if (mask && init!=3)
cimg_forXYC(img,x,y,k) if (mask(x,y))
img(x,y,k) = (float)((init?
(init==1?initial_max:((initial_max - initial_min)*cimg::rand())):
initial_min));
CImgDisplay disp;
if (visu) disp.assign(img,"Iterated Image");
CImg<> G(img.width(),img.height(),1,3,0), T(G), veloc(img), val(2), vec(2,2);
// PDE main iteration loop
//-------------------------
for (unsigned int iter = 0; iter<nb_iter &&
(!disp || (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC())); ++iter) {
std::printf("\riter %u , xdt = %g ",iter,xdt); std::fflush(stdout);
if (stflag) img.print();
if (disp && disp.is_keySPACE()) { view_t = !view_t; disp.set_key(); }
if (!(iter%skip)) {
// Compute the tensor field T, used to drive the diffusion
//---------------------------------------------------------
// When using PDE for flow visualization
if (flow) cimg_forXY(flow,x,y) {
const float
u = flow(x,y,0,0),
v = flow(x,y,0,1),
n = (float)std::sqrt((double)(u*u + v*v)),
nn = (n!=0)?n:1;
T(x,y,0) = u*u/nn;
T(x,y,1) = u*v/nn;
T(x,y,2) = v*v/nn;
} else {
// Compute structure tensor field G
CImgList<> grad = img.get_gradient();
if (alpha!=0) cimglist_for(grad,l) grad[l].blur((float)alpha);
G.fill(0);
cimg_forXYC(img,x,y,k) {
const float ix = grad[0](x,y,k), iy = grad[1](x,y,k);
G(x,y,0) += ix*ix;
G(x,y,1) += ix*iy;
G(x,y,2) += iy*iy;
}
if (sigma!=0) G.blur((float)sigma);
// When using PDE for image restoration, inpainting or zooming
T.fill(0);
if (!mask) cimg_forXY(G,x,y) {
G.get_tensor_at(x,y).symmetric_eigen(val,vec);
const float
l1 = (float)std::pow(1.0f + val[0] + val[1],-a1),
l2 = (float)std::pow(1.0f + val[0] + val[1],-a2),
ux = vec(1,0),
uy = vec(1,1);
T(x,y,0) = l1*ux*ux + l2*uy*uy;
T(x,y,1) = l1*ux*uy - l2*ux*uy;
T(x,y,2) = l1*uy*uy + l2*ux*ux;
}
else cimg_forXY(G,x,y) if (mask(x,y)) {
G.get_tensor_at(x,y).symmetric_eigen(val,vec);
const float
ux = vec(1,0),
uy = vec(1,1);
T(x,y,0) = ux*ux;
T(x,y,1) = ux*uy;
T(x,y,2) = uy*uy;
}
}
}
// Compute the PDE velocity and update the iterated image
//--------------------------------------------------------
CImg_3x3(I,float);
veloc.fill(0);
cimg_forC(img,k) cimg_for3x3(img,x,y,0,k,I,float) {
const float
a = T(x,y,0),
b = T(x,y,1),
c = T(x,y,2),
ixx = Inc + Ipc - 2*Icc,
iyy = Icn + Icp - 2*Icc,
ixy = 0.25f*(Ipp + Inn - Ipn - Inp);
veloc(x,y,k) = a*ixx + 2*b*ixy + c*iyy;
}
if (dt>0) {
float m, M = veloc.max_min(m);
xdt = dt/std::max(cimg::abs(m),cimg::abs(M));
} else xdt=-dt;
img+=veloc*xdt;
img.cut((float)initial_min,(float)initial_max);
// Display and save iterations
if (disp && !(iter%visu)) {
if (!view_t) img.display(disp);
else {
const unsigned char white[3] = {255,255,255};
CImg<unsigned char> nvisu = img.get_resize(disp.width(),disp.height()).normalize(0,255);
CImg<> isophotes(img.width(),img.height(),1,2,0);
cimg_forXY(img,x,y) if (!mask || mask(x,y)) {
T.get_tensor_at(x,y).symmetric_eigen(val,vec);
isophotes(x,y,0) = vec(0,0);
isophotes(x,y,1) = vec(0,1);
}
nvisu.draw_quiver(isophotes,white,0.5f,10,9,0).display(disp);
}
}
if (save && file_o && !(iter%save)) img.save(file_o,iter);
if (disp) disp.resize().display(img);
}
// Save result and exit.
if (file_o) img.save(file_o);
return 0;
}

114
examples/pde_heatflow2d.cpp Normal file
View file

@ -0,0 +1,114 @@
/*
#
# File : pde_heatflow2D.cpp
# ( C++ source file )
#
# Description : A simple Heat flow on 2D images.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
// Include library header file
#include "CImg.h"
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
#undef min
#undef max
// Make a simpler namespace alias if one wants to avoid 'using namespace cimg_library'
namespace cil = cimg_library;
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line arguments, and init images and displays
//-----------------------------------------------------------
cimg_usage("Perform a simple Heat Flow on 2D images");
cil::CImg<> img(cimg_option("-i",cimg_imagepath "milla.bmp","Input image")), veloc(img);
const double dt = cimg_option("-dt",3.0,"Adapting time step");
img.
noise(cimg_option("-ng",0.0,"Add gaussian noise"),0).
noise(cimg_option("-nu",0.0,"Add uniform noise"),1).
noise(cimg_option("-ns",0.0,"Add Salt&Pepper noise"),2);
cil::CImgDisplay profile(400,300,"Intensity Profile",0,false,true), disp(img,"Heat flow 2D",0,false,true);
disp.move((cil::CImgDisplay::screen_width() - disp.width() - profile.width())/2,
(cil::CImgDisplay::screen_height() - disp.height())/2);
profile.move(disp.window_x() + 8 + disp.window_width(), disp.window_y());
const float fwhite[] = { 255,255,255 };
bool run_PDE = true;
// Begin PDE iteration loop
//-------------------------
for (int iter = 0; !disp.is_closed() && !profile.is_closed() &&
!disp.is_keyQ() && !disp.is_keyESC() && !profile.is_keyQ() && !profile.is_keyESC();) {
// Compute one iteration of PDE explicit scheme
if (run_PDE) {
CImg_3x3(I,float);
cimg_forC(img,k) cimg_for3x3(img,x,y,0,k,I,float) veloc(x,y,k) = Inc + Ipc + Icn + Icp - 4*Icc;
float m, M = veloc.max_min(m);
const double xdt = dt/(M - m);
img += veloc*xdt;
cil::CImg<>(img).draw_text(2,2,"iter = %d",fwhite,0,1,13,iter).display(disp.wait(25));
}
// Plot (R,G,B) intensity profiles and display it
if (disp.mouse_x()>=0) {
const int
mx = disp.mouse_x(), my = disp.mouse_y(),
mnx = mx*profile.width()/disp.width();
const unsigned char red[] = { 255,0,0 }, green[] = { 0,255,0 }, blue[] = { 0,0,255 }, white[] = { 255,255,255 };
cil::CImg<unsigned char>(profile.width(),profile.height(),1,3,0).
draw_graph(img.get_shared_row(my,0,0),red,1,1,0,255,0).
draw_graph(img.get_shared_row(my,0,1),green,1,1,0,255,0).
draw_graph(img.get_shared_row(my,0,2),blue,1,1,0,255,0).
draw_line(mnx,0,mnx,profile.height() - 1,white,0.5f,cil::cimg::rol(0xFF00FF00,iter%32)).
draw_text(2,2,"(x,y)=(%d,%d)",white,0,1,13,mx,my).
display(profile);
}
// Mouse button stops/starts PDE evolution.
if (disp.button() || profile.button()) { disp.set_button(); profile.set_button(); run_PDE = !run_PDE; }
profile.resize();
disp.resize(disp);
if (run_PDE) ++iter;
}
return 0;
}

73
examples/plotter1d.cpp Normal file
View file

@ -0,0 +1,73 @@
/*
#
# File : plotter1d.cpp
# ( C++ source file )
#
# Description : A simple math formula plotter.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
// Include CImg library file and use its main namespace
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line argument.
cimg_usage("Simple plotter of mathematical formulas");
const char *const formula = cimg_option("-f","sin(x/8) % cos(2*x)","Formula to plot");
const float x0 = cimg_option("-x0",-5.0f,"Minimal X-value");
const float x1 = cimg_option("-x1",5.0f,"Maximal X-value");
const int resolution = cimg_option("-r",1024,"Plot resolution");
const unsigned int nresolution = resolution>1?resolution:1024;
const unsigned int plot_type = cimg_option("-p",1,"Plot type");
const unsigned int vertex_type = cimg_option("-v",1,"Vertex type");
// Create plot data.
CImg<double> values(4,nresolution,1,1,0);
const unsigned int r = nresolution - 1;
cimg_forY(values,X) values(0,X) = x0 + X*(x1 - x0)/r;
cimg::eval(formula,values).move_to(values);
// Display interactive plot window.
values.display_graph(formula,plot_type,vertex_type,"X-axis",x0,x1,"Y-axis");
// Quit.
return 0;
}

View file

@ -0,0 +1,379 @@
/*
#
# File : radon_transform2d.cpp
# ( C++ source file )
#
# Description : An implementation of the Radon Transform.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David G. Starkweather
# ( starkdg@sourceforge.net - starkweatherd@cox.net )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
#define ROUNDING_FACTOR(x) (((x) >= 0) ? 0.5 : -0.5)
CImg<double> GaussianKernel(double rho);
CImg<float> ApplyGaussian(CImg<unsigned char> im,double rho);
CImg<unsigned char> RGBtoGrayScale(CImg<unsigned char> &im);
int GetAngle(int dy,int dx);
CImg<unsigned char> CannyEdges(CImg<float> im, double T1, double T2,bool doHysteresis);
CImg<> RadonTransform(CImg<unsigned char> im,int N);
// Main procedure
//----------------
int main(int argc,char **argv) {
cimg_usage("Illustration of the Radon Transform");
const char *file = cimg_option("-f",cimg_imagepath "parrot.ppm","path and file name");
const double sigma = cimg_option("-r",1.0,"blur coefficient for gaussian low pass filter (lpf)"),
thresh1 = cimg_option("-t1",0.50,"lower threshold for canny edge detector"),
thresh2 = cimg_option("-t2",1.25,"upper threshold for canny edge detector");;
const int N = cimg_option("-n",64,"number of angles to consider in the Radon transform - should be a power of 2");
//color to draw lines
const unsigned char green[] = {0,255,0};
CImg<unsigned char> src(file);
int rhomax = (int)std::sqrt((double)(src.width()*src.width() + src.height()*src.height()))/2;
if (cimg::dialog(cimg::basename(argv[0]),
"Instructions:\n"
"Click on space bar or Enter key to display Radon transform of given image\n"
"Click on anywhere in the transform window to display a \n"
"corresponding green line in the original image\n",
"Start", "Quit",0,0,0,0,
src.get_resize(100,100,1,3),true)) std::exit(0);
//retrieve a grayscale from the image
CImg<unsigned char> grayScaleIm;
if ((src.spectrum() == 3) && (src.width() > 0) && (src.height() > 0) && (src.depth() == 1))
grayScaleIm = (CImg<unsigned char>)src.get_norm(0).quantize(255,false);
else if ((src.spectrum() == 1)&&(src.width() > 0) && (src.height() > 0) && (src.depth() == 1))
grayScaleIm = src;
else { // image in wrong format
if (cimg::dialog(cimg::basename("wrong file format"),
"Incorrect file format\n","OK",0,0,0,0,0,
src.get_resize(100,100,1,3),true)) std::exit(0);
}
//blur the image with a Gaussian lpf to remove spurious edges (e.g. noise)
CImg<float> blurredIm = ApplyGaussian(grayScaleIm,sigma);
//use canny edge detection algorithm to get edge map of the image
//- the threshold values are used to perform hysteresis in the edge detection process
CImg<unsigned char> cannyEdgeMap = CannyEdges(blurredIm,thresh1,thresh2,false);
CImg<unsigned char> radonImage(500,400,1,1,0);
//display the two windows
CImgDisplay dispImage(src,"original image");
dispImage.move(CImgDisplay::screen_width()/8,CImgDisplay::screen_height()/8);
CImgDisplay dispRadon(radonImage,"Radon Transform");
dispRadon.move(CImgDisplay::screen_width()/4,CImgDisplay::screen_height()/4);
CImgDisplay dispCanny(cannyEdgeMap,"canny edges");
//start main display loop
while (!dispImage.is_closed() && !dispRadon.is_closed() &&
!dispImage.is_keyQ() && !dispRadon.is_keyQ() &&
!dispImage.is_keyESC() && !dispRadon.is_keyESC()) {
CImgDisplay::wait(dispImage,dispRadon);
if (dispImage.is_keySPACE() || dispRadon.is_keySPACE()) {
radonImage = (CImg<unsigned char>)RadonTransform(cannyEdgeMap,N).quantize(255,false).resize(500,400);
radonImage.display(dispRadon);
}
//when clicking on dispRadon window, draw line in original image window
if (dispRadon.button())
{
const double rho = dispRadon.mouse_y()*rhomax/dispRadon.height(),
theta = (dispRadon.mouse_x()*N/dispRadon.width())*2*cimg::PI/N,
x = src.width()/2 + rho*std::cos(theta),
y = src.height()/2 + rho*std::sin(theta);
const int x0 = (int)(x + 1000*std::cos(theta + cimg::PI/2)),
y0 = (int)(y + 1000*std::sin(theta + cimg::PI/2)),
x1 = (int)(x - 1000*std::cos(theta + cimg::PI/2)),
y1 = (int)(y - 1000*std::sin(theta + cimg::PI/2));
src.draw_line(x0,y0,x1,y1,green,1.0f,0xF0F0F0F0).display(dispImage);
}
}
return 0;
}
/**
* PURPOSE: create a 5x5 gaussian kernel matrix
* PARAM rho - gaussiam equation parameter (default = 1.0)
* RETURN CImg<double> the gaussian kernel
**/
CImg<double> GaussianKernel(double sigma = 1.0)
{
CImg<double> resultIm(5,5,1,1,0);
int midX = 3, midY = 3;
cimg_forXY(resultIm,X,Y) {
resultIm(X,Y) = std::ceil(256.0*(std::exp(-(midX*midX + midY*midY)/(2*sigma*sigma)))/(2*cimg::PI*sigma*sigma));
}
return resultIm;
}
/*
* PURPOSE: convolve a given image with the gaussian kernel
* PARAM CImg<unsigned char> im - image to be convolved upon
* PARAM double sigma - gaussian equation parameter
* RETURN CImg<float> image resulting from the convolution
* */
CImg<float> ApplyGaussian(CImg<unsigned char> im,double sigma)
{
CImg<float> smoothIm(im.width(),im.height(),1,1,0);
//make gaussian kernel
CImg<float> gk = GaussianKernel(sigma);
//apply gaussian
CImg_5x5(I,int);
cimg_for5x5(im,X,Y,0,0,I,int) {
float sum = 0;
sum += gk(0,0)*Ibb + gk(0,1)*Ibp + gk(0,2)*Ibc + gk(0,3)*Ibn + gk(0,4)*Iba;
sum += gk(1,0)*Ipb + gk(1,1)*Ipp + gk(1,2)*Ipc + gk(1,3)*Ipn + gk(1,4)*Ipa;
sum += gk(2,0)*Icb + gk(2,1)*Icp + gk(2,2)*Icc + gk(2,3)*Icn + gk(2,4)*Ica;
sum += gk(3,0)*Inb + gk(3,1)*Inp + gk(3,2)*Inc + gk(3,3)*Inn + gk(3,4)*Ina;
sum += gk(4,0)*Iab + gk(4,1)*Iap + gk(4,2)*Iac + gk(4,3)*Ian + gk(4,4)*Iaa;
smoothIm(X,Y) = sum/256;
}
return smoothIm;
}
/**
* PURPOSE: convert a given rgb image to a MxNX1 single vector grayscale image
* PARAM: CImg<unsigned char> im - rgb image to convert
* RETURN: CImg<unsigned char> grayscale image with MxNx1x1 dimensions
**/
CImg<unsigned char> RGBtoGrayScale(CImg<unsigned char> &im)
{
CImg<unsigned char> grayImage(im.width(),im.height(),im.depth(),1,0);
if (im.spectrum() == 3) {
cimg_forXYZ(im,X,Y,Z) {
grayImage(X,Y,Z,0) = (unsigned char)(0.299*im(X,Y,Z,0) + 0.587*im(X,Y,Z,1) + 0.114*im(X,Y,Z,2));
}
}
grayImage.quantize(255,false);
return grayImage;
}
/**
* PURPOSE: aux. function used by CannyEdges to quantize an angle theta given by gradients, dx and dy
* into 0 - 7
* PARAM: dx,dy - gradient magnitudes
* RETURN int value between 0 and 7
**/
int GetAngle(int dy,int dx)
{
double angle = cimg::abs(std::atan2((double)dy,(double)dx));
if ((angle >= -cimg::PI/8)&&(angle <= cimg::PI/8))//-pi/8 to pi/8 => 0
return 0;
else if ((angle >= cimg::PI/8)&&(angle <= 3*cimg::PI/8))//pi/8 to 3pi/8 => pi/4
return 1;
else if ((angle > 3*cimg::PI/8)&&(angle <= 5*cimg::PI/8))//3pi/8 to 5pi/8 => pi/2
return 2;
else if ((angle > 5*cimg::PI/8)&&(angle <= 7*cimg::PI/8))//5pi/8 to 7pi/8 => 3pi/4
return 3;
else if (((angle > 7*cimg::PI/8) && (angle <= cimg::PI)) ||
((angle <= -7*cimg::PI/8)&&(angle >= -cimg::PI))) //-7pi/8 to -pi OR 7pi/8 to pi => pi
return 4;
else return 0;
}
/**
* PURPOSE: create an edge map of the given image with hysteresis using thresholds T1 and T2
* PARAMS: CImg<float> im the image to perform edge detection on
* T1 lower threshold
* T2 upper threshold
* RETURN CImg<unsigned char> edge map
**/
CImg<unsigned char> CannyEdges(CImg<float> im, double T1, double T2, bool doHysteresis=false)
{
CImg<unsigned char> edges(im);
CImg<float> secDerivs(im);
secDerivs.fill(0);
edges.fill(0);
CImgList<float> gradients = im.get_gradient("xy",1);
int image_width = im.width();
int image_height = im.height();
cimg_forXY(im,X,Y) {
double Gr = std::sqrt(std::pow((double)gradients[0](X,Y),2.0) + std::pow((double)gradients[1](X,Y),2.0));
double theta = GetAngle(Y,X);
//if Gradient magnitude is positive and X,Y within the image
//take the 2nd deriv in the appropriate direction
if ((Gr > 0)&&(X < image_width - 2)&&(Y < image_height - 2)) {
if (theta == 0)
secDerivs(X,Y) = im(X + 2,Y) - 2*im(X + 1,Y) + im(X,Y);
else if (theta == 1)
secDerivs(X,Y) = im(X + 2,Y + 2) - 2*im(X + 1,Y + 1) + im(X,Y);
else if (theta == 2)
secDerivs(X,Y) = im(X,Y + 2) - 2*im(X,Y + 1) + im(X,Y);
else if (theta == 3)
secDerivs(X,Y) = im(X + 2,Y + 2) - 2*im(X + 1,Y + 1) + im(X,Y);
else if (theta == 4)
secDerivs(X,Y) = im(X + 2,Y) - 2*im(X + 1,Y) + im(X,Y);
}
}
//for each 2nd deriv that crosses a zero point and magnitude passes the upper threshold.
//Perform hysteresis in the direction of the gradient, rechecking the gradient
//angle for each pixel that meets the threshold requirement. Stop checking when
//the lower threshold is not reached.
CImg_5x5(I,float);
cimg_for5x5(secDerivs,X,Y,0,0,I,float) {
if ( (Ipp*Ibb < 0) ||
(Ipc*Ibc < 0)||
(Icp*Icb < 0) ) {
double Gr = std::sqrt(std::pow((double)gradients[0](X,Y),2.0) + std::pow((double)gradients[1](X,Y),2.0));
int dir = GetAngle(Y,X);
int Xt = X, Yt = Y, delta_x = 0, delta_y=0;
double GRt = Gr;
if (Gr >= T2)
edges(X,Y) = 255;
//work along the gradient in one direction
if (doHysteresis) {
while ((Xt > 0) && (Xt < image_width - 1) && (Yt > 0) && (Yt < image_height - 1)) {
switch (dir){
case 0 : delta_x=0;delta_y=1;break;
case 1 : delta_x=1;delta_y=1;break;
case 2 : delta_x=1;delta_y=0;break;
case 3 : delta_x=1;delta_y=-1;break;
case 4 : delta_x=0;delta_y=1;break;
}
Xt += delta_x;
Yt += delta_y;
GRt = std::sqrt(std::pow((double)gradients[0](Xt,Yt),2.0) + std::pow((double)gradients[1](Xt,Yt),2.0));
dir = GetAngle(Yt,Xt);
if (GRt >= T1)
edges(Xt,Yt) = 255;
}
//work along gradient in other direction
Xt = X; Yt = Y;
while ((Xt > 0) && (Xt < image_width - 1) && (Yt > 0) && (Yt < image_height - 1)) {
switch (dir){
case 0 : delta_x=0;delta_y=1;break;
case 1 : delta_x=1;delta_y=1;break;
case 2 : delta_x=1;delta_y=0;break;
case 3 : delta_x=1;delta_y=-1;break;
case 4 : delta_x=0;delta_y=1;break;
}
Xt -= delta_x;
Yt -= delta_y;
GRt = std::sqrt(std::pow((double)gradients[0](Xt,Yt),2.0) + std::pow((double)gradients[1](Xt,Yt),2.0));
dir = GetAngle(Yt,Xt);
if (GRt >= T1)
edges(Xt,Yt) = 255;
}
}
}
}
return edges;
}
/**
* PURPOSE: perform radon transform of given image
* PARAM: CImg<unsigned char> im - image to detect lines
* int N - number of angles to consider (should be a power of 2)
* (the values of N will be spread over 0 to 2PI)
* RETURN CImg<unsigned char> - transform of given image of size, N x D
* D = rhomax = sqrt(dimx*dimx + dimy*dimy)/2
**/
CImg<> RadonTransform(CImg<unsigned char> im,int N) {
int image_width = im.width();
int image_height = im.height();
//calc offsets to center the image
float xofftemp = image_width/2.0f - 1;
float yofftemp = image_height/2.0f - 1;
int xoffset = (int)std::floor(xofftemp + ROUNDING_FACTOR(xofftemp));
int yoffset = (int)std::floor(yofftemp + ROUNDING_FACTOR(yofftemp));
float dtemp = (float)std::sqrt((double)(xoffset*xoffset + yoffset*yoffset));
int D = (int)std::floor(dtemp + ROUNDING_FACTOR(dtemp));
CImg<> imRadon(N,D,1,1,0);
//for each angle k to consider
for (int k= 0 ; k < N; k++) {
//only consider from PI/8 to 3PI/8 and 5PI/8 to 7PI/8
//to avoid computational complexity of a steep angle
if (k == 0){k = N/8;continue;}
else if (k == (3*N/8 + 1)){ k = 5*N/8;continue;}
else if (k == 7*N/8 + 1){k = N; continue;}
//for each rho length, determine linear equation and sum the line
//sum is to sum the values along the line at angle k2pi/N
//sum2 is to sum the values along the line at angle k2pi/N + N/4
//The sum2 is performed merely by swapping the x,y axis as if the image were rotated 90 degrees.
for (int d=0; d < D; d++) {
double theta = 2*k*cimg::PI/N;//calculate actual theta
double alpha = std::tan(theta + cimg::PI/2);//calculate the slope
double beta_temp = -alpha*d*std::cos(theta) + d*std::sin(theta);//y-axis intercept for the line
int beta = (int)std::floor(beta_temp + ROUNDING_FACTOR(beta_temp));
//for each value of m along x-axis, calculate y
//if the x,y location is within the boundary for the respective image orientations, add to the sum
unsigned int sum1 = 0,
sum2 = 0;
int M = (image_width >= image_height) ? image_width : image_height;
for (int m=0;m < M; m++) {
//interpolate in-between values using nearest-neighbor approximation
//using m,n as x,y indices into image
double n_temp = alpha*(m - xoffset) + beta;
int n = (int)std::floor(n_temp + ROUNDING_FACTOR(n_temp));
if ((m < image_width) && (n + yoffset >= 0) && (n + yoffset < image_height))
{
sum1 += im(m, n + yoffset);
}
n_temp = alpha*(m - yoffset) + beta;
n = (int)std::floor(n_temp + ROUNDING_FACTOR(n_temp));
if ((m < image_height)&&(n + xoffset >= 0)&&(n + xoffset < image_width))
{
sum2 += im(-(n + xoffset) + image_width - 1, m);
}
}
//assign the sums into the result matrix
imRadon(k,d) = (float)sum1;
//assign sum2 to angle position for theta + PI/4
imRadon(((k + N/4)%N),d) = (float)sum2;
}
}
return imRadon;
}
/* references:
* 1. See Peter Toft's thesis on the Radon transform: http://petertoft.dk/PhD/index.html
* While I changed his basic algorithm, the main idea is still the same and provides an excellent explanation.
*
* */

142
examples/scene3d.cpp Normal file
View file

@ -0,0 +1,142 @@
/*
#
# File : scene3d.cpp
# ( C++ source file )
#
# Description : A simple program that demonstrates the use of the
# 3D functions of CImg, in conjonction with the Board library.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
// Uncomment the line below to use the Board library.
// ( You will need to link your code with the board library object ).
// ( Get the Board Library at : http://libboard.sourceforge.net/ )
//#define cimg_use_board
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main() {
// Define a simple 3D scene, composed of various basic objects (torus, cone, cube, ...)
//-------------------------------------------------------------------------------------
std::fprintf(stderr," - Create 3D Scene.\n");
// Define objects vertices and primitives.
CImgList<unsigned int> cube_prims, cone_prims, torus_prims, sphere_prims, plane_prims, scene_prims;
const CImg<float>
cube_pts = CImg<>::box3d(cube_prims,60,60,60).shift_object3d().shift_object3d(-50,50,0),
cone_pts = CImg<>::cone3d(cone_prims,30,40).shift_object3d().shift_object3d(50,50,0),
torus_pts = CImg<>::torus3d(torus_prims,30,10).shift_object3d().shift_object3d(-50,-50,0),
sphere_pts = CImg<>::sphere3d(sphere_prims,30).shift_object3d().shift_object3d(50,-50,0),
plane_pts = CImg<>::plane3d(plane_prims,200,200,20,20).shift_object3d().shift_object3d(0,0,40);
plane_prims.insert(plane_prims.get_reverse_object3d());
// Define objects colors and textures.
const CImgList<unsigned char>
cone_cols = CImgList<unsigned char>(cone_prims.size(),CImg<unsigned char>::vector(128,63,255)),
torus_cols = CImgList<unsigned char>(torus_prims.size(),CImg<unsigned char>::vector(255,55,163)),
sphere_cols = CImgList<unsigned char>(sphere_prims.size(),CImg<unsigned char>::vector(115,115,63)),
plane_cols = CImgList<unsigned char>(plane_prims.size(),CImg<unsigned char>::vector(60,120,180));
const CImg<unsigned char> texture = CImg<unsigned char>(cimg_imagepath "milla.bmp").resize(128,128);
CImgList<unsigned char> cube_cols;
cimglist_for(cube_prims,p) {
cube_cols.insert(texture,~0U,true);
cube_prims[p].append(CImg<unsigned int>::vector(0,0,127,0,127,127,0,127),'y');
}
// Define objects opacities.
const CImg<float>
cube_opacs(cube_prims.size(),1,1,1,1.0f),
cone_opacs(cone_prims.size(),1,1,1,0.8f),
torus_opacs(torus_prims.size(),1,1,1,0.6f),
sphere_opacs(sphere_prims.size(),1,1,1,0.4f),
plane_opacs(plane_prims.size(),1,1,1,0.4f);
// Append all object in a single 3D scene.
const CImg<float> scene_pts = CImg<float>().
append_object3d(scene_prims,cube_pts,cube_prims).
append_object3d(scene_prims,cone_pts,cone_prims).
append_object3d(scene_prims,torus_pts,torus_prims).
append_object3d(scene_prims,sphere_pts,sphere_prims).
append_object3d(scene_prims,plane_pts,plane_prims);
const CImgList<unsigned char> scene_cols = (+cube_cols,cone_cols,torus_cols,sphere_cols,plane_cols);
const CImg<float> scene_opacs = (cube_opacs,cone_opacs,torus_opacs,sphere_opacs,plane_opacs)>'x';
// Display object3D in a user-interacted window and get final position matrix.
std::fprintf(stderr," - Display 3D Scene.\n");
const CImg<unsigned char> visu = CImg<unsigned char>(3,512,512,1).fill(230,230,255).permute_axes("yzcx");
CImg<float> view_matrix = CImg<>::identity_matrix(4);
visu.display_object3d("3D Scene",scene_pts,scene_prims,scene_cols,scene_opacs,true,4,4,false,
500.0f,0,0,-5000,0.5f,0.1f,true,view_matrix.data());
// Save object 3D as OFF file.
std::fprintf(stderr," - Save .OFF 3D object file.\n");
scene_pts.save_off(scene_prims,scene_cols,"output.off");
// Save 3D view in SVG, EPS and FIG files.
// (using the Board library : https://github.com/c-koi/libboard ).
#ifdef cimg_use_board
// Define a Board instance
LibBoard::Board B;
// Set Background color of the board.
B.clear(230,230,255);
// Draw object both in 'visu' and in the board.
(view_matrix.crop(0,0,2,2))*=2;
(+visu).draw_object3d(B,visu.width()/2,visu.height()/2,visu.depth()/2,
view_matrix*scene_pts,scene_prims,scene_cols,scene_opacs,3).
display("Snapshot for Board");
// Save board into a vector graphics file format.
std::fprintf(stderr," - Save .SVG, .EPS and .FIG snapshots\n");
B.save("output.svg");
B.save("output.eps");
B.save("output.fig");
#endif
// Exit.
std::fprintf(stderr," - Exit.\n");
return 0;
}

View file

@ -0,0 +1,113 @@
/*
#
# File : spherical_function3d.cpp
# ( C++ source file )
#
# Description : An example that shows how to build custom 3D objects in CImg.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
/*---------------------------
Main procedure
--------------------------*/
int main() {
CImgList<unsigned char> object_colors;
CImgList<float> object_opacities;
// Define a 3D centered box.
CImg<float> object_vertices = CImg<float>(3,8,1,1, // Define the 8 vertices of the cube
-1,-1,-1, // (x0,y0,z0)
1,-1,-1, // (x1,y1,z1)
1,1,-1, // ...
-1,1,-1,
-1,-1,1,
1,-1,1,
1,1,1, // (x6,y6,z6)
-1,1,1).transpose(); // (x7,y7,z7)
CImgList<unsigned int> object_primitives(12,1,2,1,1, // Define the 12 segments of the cube
0,1, 1,2, 2,3, 3,0,
4,5, 5,6, 6,7, 7,4,
0,4, 1,5, 2,6, 3,7);
object_colors.insert(object_primitives.size(),CImg<unsigned char>::vector(32,64,255));
object_opacities.insert(object_primitives.size(),CImg<float>::vector(0.3f));
// Define the spherical function's vertices.
CImgList<float> spherical_vertices;
const float a = 1;
const unsigned int na = 132, nb = 132;
for (unsigned int v = 0; v<na; ++v)
for (unsigned int u = 0; u<nb; ++u) {
const float
alpha = (float)(u*2*cimg::PI/nb),
beta = (float)(-cimg::PI/2 + v*cimg::PI/na),
x = (float)((a*std::cos(beta))*std::cos(alpha)),
y = (float)((a*std::cos(beta))*std::sin(alpha)),
z = (float)(a*std::sin(beta)),
altitude = cimg::abs(1 + 0.8f*std::cos(3*alpha)*std::sin(4*beta));
spherical_vertices.insert(CImg<float>::vector(altitude*x,altitude*y,altitude*z));
}
// Define the spherical function's mesh.
CImgList<unsigned int> spherical_primitives;
for (unsigned int vv = 0; vv<na - 1; ++vv)
for (unsigned int uu = 0; uu<nb; ++uu) {
const int nv = (vv + 1)%na, nu = (uu + 1)%nb;
spherical_primitives.insert(CImg<unsigned int>::vector(nb*vv + nu,nb*nv + uu,nb*vv + uu));
spherical_primitives.insert(CImg<unsigned int>::vector(nb*vv + nu,nb*nv + nu,nb*nv + uu));
object_colors.insert(CImg<>::vector(0,255,255));
object_colors.insert(CImg<>::vector(100,200,255));
object_opacities.insert(2,CImg<>::vector(1));
}
// Merge 3D objects together.
object_vertices.append_object3d(object_primitives,spherical_vertices>'x',spherical_primitives);
char title[4096] = { 0 };
std::sprintf(title,"3D Spherical Function (%u vertices, %u primitives)",
object_vertices.width(),object_primitives.size());
CImgDisplay disp(640,480,title,0);
CImg<unsigned char>(disp.width(),disp.height(),1,3,220).
display_object3d(disp,object_vertices,object_primitives,object_colors,object_opacities,true,4,3,false,
500,0,0,-5000,0.1f,1.5f);
return 0;
}

208
examples/tetris.cpp Normal file
View file

@ -0,0 +1,208 @@
/*
#
# File : tetris.cpp
# ( C++ source file )
#
# Description : A CImg version of the famous Tetris game.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "img/tetris.h"
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line argument (if any)
cimg_usage("An implementation of the well known 'Tetris' game with CImg.");
unsigned int
blocdim = cimg_option("-blocdim",18,"Sprite bloc size"),
speed = cimg_option("-speed",20,"Initial speed"),
level = cimg_option("-level",0,"Level");
const char *geometry = cimg_option("-g","12x20","Size of the board");
unsigned int bwidth = 12,bheight = 20;
std::sscanf(geometry,"%u%*c%u",&bwidth,&bheight);
const CImg<unsigned char> dlogo = CImg<unsigned char>(data_logo,128,96,1,3,true);
if (cimg::dialog("CImg Tetris",
"Welcome to the CImg version of Tetris.\n"
"( by David Tschumperle )\n\n"
"Press 'Start' when you are ready to play !","Start","Quit",0,0,0,0,dlogo,true)) std::exit(0);
// Create sprite, background graphics and initial board data
const CImgList<unsigned char> pieces = CImgList<unsigned char>().
insert(CImg<unsigned char>(3,2).fill(1,1,1,0,0,1)).
insert(CImg<unsigned char>(3,2).fill(2,2,2,2,0,0)).
insert(CImg<unsigned char>(2,2).fill(3,3,3,3)).
insert(CImg<unsigned char>(4,1).fill(4,4,4,4)).
insert(CImg<unsigned char>(3,2).fill(5,5,0,0,5,5)).
insert(CImg<unsigned char>(3,2).fill(0,6,6,6,6,0)).
insert(CImg<unsigned char>(3,3).fill(0,7,0,7,7,7,0,7,0)).
insert(CImg<unsigned char>(2,1).fill(8,8)).
insert(CImg<unsigned char>(3,2).fill(9,9,9,0,9,0)).
insert(CImg<unsigned char>(2,2).fill(10,10,0,10)).
insert(CImg<unsigned char>(3,1).fill(11,11,11));
CImg<unsigned char> board(bwidth,bheight,1,1,0), background(board.width()*blocdim,board.height()*blocdim,1,3,0);
(background.noise(30).draw_plasma().noise(30).deriche(5,0,'y').shift(0,-background.height()/2,0,0,2).
deriche(5,0,'y'))/=1.5f;
if (level) (board.get_shared_rows(board.height() - level,board.height() - 1,0,0).noise(100))%=pieces.size() + 1;
// Create a set of small gradient-colored blocs used to draw the pieces.
CImgList<unsigned char> blocs(pieces.size(),blocdim,blocdim,1,3);
cimglist_for(blocs,l) {
CImg<unsigned char> color = CImg<unsigned char>(3,1,1,1,128).noise(127,1).cut(120,255);
float val;
cimg_forXYC(blocs[l],x,y,k)
blocs[l](x,y,k) = (unsigned char)((val=(color[k]*0.7f*(x + y + 5)/blocdim))>255?255:val);
blocs[l].draw_line(0,0,0,blocdim - 1,(color>>1).data()).
draw_line(0,blocdim - 1,blocdim - 1,blocdim - 1,(color>>1).data());
color = (CImg<unsigned int>(color)*=2).cut(0,255);
blocs[l].draw_line(0,0,(int)blocdim - 1,0,color.data()).
draw_line(blocdim - 1,0,blocdim - 1,blocdim - 1,color.data());
}
// Initialize window display and enter the main event loop
CImgDisplay disp(background,"CImg Tetris",0,false,true);
disp.move((CImgDisplay::screen_width() - disp.width())/2,
(CImgDisplay::screen_height() - disp.height())/2).hide_mouse();
const unsigned char white[3]={ 255, 255, 255 };
CImg<unsigned char> visu, nboard, piece, next, next_mask;
int cx = -1, cy = -1, cn = -1, nn = rand()%pieces.size(), time = 0, score = 0;
bool gameover = false, pause = false;
while (!gameover && !disp.is_closed() && !disp.is_keyESC() && !disp.is_keyQ()) {
if (!pause) {
// Draw the board on the display window.
nboard = board; visu = background;
if (cx>=0 && cy>=0)
cimg_forXY(piece,x,y) if (piece(x,y)) nboard(cx - piece.width()/2 + x,cy - piece.height()/2 + y)=piece(x,y);
cimg_forXY(board,xx,yy) if (nboard(xx,yy)) visu.draw_image(xx*blocdim,yy*blocdim,blocs[nboard(xx,yy) - 1]);
visu.draw_text(5,5,"Lines : %d",white,0,1,13,score,nn).draw_text(visu.width() - 75,5,"Next :",white,0,1,13);
if (next) visu.draw_image(visu.width() - next.width() - 2,10 - next.height()/2,next,next_mask).
display(disp.wait(20));
if (cn<0) {
// Introduce a new piece on the board (if necessary) and create representation of the next piece
board = nboard;
piece = pieces[cn=nn];
nn = rand()%pieces.size();
cx = board.width()/2;
cy = piece.height()/2;
next = CImg<unsigned char>(pieces[nn].width()*blocdim,pieces[nn].height()*blocdim,1,3,0);
cimg_forXY(pieces[nn],xi,yi)
if (pieces[nn](xi,yi)) next.draw_image(xi*blocdim,yi*blocdim,blocs[pieces[nn](xi,yi) - 1]);
next_mask = next.resize(-50,-50).get_norm().threshold(0);
// Detect tetris lines and do line removal animation if found.
cimg_forY(board,yyy) {
int Y = yyy*blocdim, line = 1;
cimg_forX(board,xxx) if (!board(xxx,yyy)) line=0;
if (line) {
board.draw_image(0,1,board.get_crop(0,0,board.width() - 1,yyy - 1));
if (!((++score)%1) && speed>1) --speed;
for (float alpha=0; alpha<=1; alpha+=0.07f)
CImg<unsigned char>(visu).draw_image(0,Y,background.get_crop(0,Y,visu.width() - 1,
Y + blocdim - 1),alpha).
display(disp.wait(20));
visu.draw_image(0,Y,background.get_crop(0,Y,visu.width() - 1,Y + blocdim - 1));
}
}
}
// Handle motion & collisions
const int ox = cx, oy = cy;
bool rotated = false, collision;
switch (disp.key()) {
case cimg::keyP: pause = true; break;
case cimg::keyARROWUP: piece.rotate(90); rotated = true; disp.set_key(); break;
case cimg::keyARROWLEFT: --cx; disp.set_key(); break;
case cimg::keyARROWRIGHT: ++cx; disp.set_key(); break;
}
if (cx - piece.width()/2<0) cx = piece.width()/2;
if (cy - piece.height()/2<0) cy = piece.height()/2;
if (cx + (piece.width() - 1)/2>=board.width()) cx = board.width() - 1 - (piece.width() - 1)/2;
// Detect collision along the X axis
collision = false;
cimg_forXY(piece,i,j)
if (piece(i,j) && board(cx - piece.width()/2 + i,cy - piece.height()/2 + j)) collision = true;
if (collision) { cx=ox; if (rotated) piece.rotate(-90); }
if (disp.key()==cimg::keyARROWDOWN || !((++time)%speed)) { ++cy; disp.set_key(); }
// Detect collisiong along the Y axis
collision = false;
cimg_forXY(piece,ii,jj)
if (piece(ii,jj) && (cy - piece.height()/2 + jj>=board.height() ||
board(cx - piece.width()/2 + ii,cy - piece.height()/2 + jj))) collision = true;
if (collision || cy + (piece.height() - 1)/2>=board.height()) { cy = oy; cn = -1; }
if (collision && cy==piece.height()/2) gameover = true;
} else {
// If game is paused (key 'P'), do a little text animation
float A = 0, B = 0;
CImg<float> pauselogo = CImg<unsigned char>().draw_text(0,0,"Game Paused\nPress a key",white);
disp.set_key(); while (!disp.is_closed() && !disp.key()) {
const CImg<float> pauserotated = pauselogo.get_rotate((float)(30*std::sin(A)),1,0).
resize((int)(-150 - 80*std::sin(B)),(int)(-150 - 80*std::sin(B)));
A+=0.08f; B+=0.043f;
CImg<unsigned char>(background).
draw_image((background.width() - pauserotated.width())/2,
(background.height() - pauserotated.height())/2,
pauserotated.get_resize(-100,-100,1,3,2),pauserotated,1,255).display(disp.wait(20));
if (disp.is_resized()) disp.resize();
}
disp.set_key();
pause = false;
}
background.shift(0,-20/(int)speed,0,0,2);
if (disp.is_resized()) disp.resize();
}
// End of game reached, display the score and do a 'game over' animation
cimg_forXYC(visu,x,y,k) if (x%2 || y%2) visu(x,y,k) = 0;
visu.display(disp);
char tmp[1024];
std::sprintf(tmp,"Game Over !\n\nYour score : %d",score);
cimg::dialog("CImg Tetris",tmp,"Quit");
return 0;
}

190
examples/tron.cpp Normal file
View file

@ -0,0 +1,190 @@
/*
#
# File : tron.cpp
# ( C++ source file )
#
# Description : A clone of the famous (and very simple) Tron game.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main(int argc, char **argv) {
// Print usage, help and retrieve command line options
//-----------------------------------------------------
cimg_usage("A very simple Tron game, using the CImg Library");
cimg_help("--- Quick help ----------------------------\n"
" Player 1 (blue) :\n"
" Use keys 'Z' (up), 'S' (down), 'Q' (left)\n"
" and 'D' (right) to control your player.\n"
" Right 'CONTROL' key enables turbospeed\n"
" Player 2 (red) : \n"
" Use arrow keys to control your player.\n"
" 'TAB' key enables turbospeed.\n"
"-------------------------------------------");
const char *geom = cimg_option("-g","300x300","Size of the game board");
const int delay = cimg_option("-s",10,"Game speed (lower value means faster)");
const bool twoplayers = !cimg_option("-1",false,"One player only");
const int zoom = cimg_option("-z",1,"Zoom factor");
const bool full = cimg_option("-f",false,"Fullscreen mode");
unsigned int W = 400, H = 400;
std::sscanf(geom,"%u%*c%u",&W,&H);
// Define game colors and variables
//----------------------------------
const unsigned char blue[] = { 128,200,255}, red[] = { 255,0,0 }, white[] = { 255,255,255 };
int score1 = 0, score2 = 0, round_over = 0, ix1 = -1, iy1 = -1, x1 = 0, y1 = 0, u1 = 0, v1 = 0,
ix2 = -1, iy2 = -1, x2 = 0, y2 = 0, u2 = 0, v2 = 0;
bool start_round = true, turbo1 = false, turbo2 = false;
// Create background image
//--------------------------
CImg<unsigned char> background, img;
background.assign(64,64,1,3,0).noise(60).draw_plasma().resize(W,H).blur(2).normalize(0,128).
draw_rectangle(0,0,W-1,H-1,white,1.0f,~0U);
// Open display window
//---------------------
CImgDisplay disp(background,"* CImg-Tron *");
if (zoom>1) disp.resize(-100*zoom,-100*zoom);
if (full) disp.toggle_fullscreen().display(background);
// Start main game loop
//----------------------
while (!disp.is_closed() && !disp.is_keyESC()) {
// Init new game round if necessary
//----------------------------------
if (start_round) {
// Init game variables
round_over = 0;
ix1 = -1; iy1 = -1; x1 = 10; y1 = 10; u1 = 1; v1 = 0; turbo1 = false;
ix2 = -1; iy2 = -1; x2 = W - 11; y2 = H - 11; u2 = -1; v2 = 0; turbo2 = false;
img = background;
start_round = false;
// Display a simple pre-round page
CImg<unsigned char> logo, pressakey;
logo.draw_text(0,0," CImg-Tron ",white,0,1,33).resize(-100,-100,1,3);
CImg<unsigned char> tmp = (+background).draw_image((W - logo.width())/2,(H - logo.height())/2 - 20,
logo,logo.get_channel(0).dilate(6).normalize(0,1)).
draw_text(W/2 - 60,H/2 + 10,"Blue ( %u )",blue,0,1,13,score1).
draw_text(W/2 + 10,H/2 + 10,"Red ( %u )",red,0,1,13,score2);
pressakey.draw_text(0,0,"* Press a key to start round *",white);
for (float i = 0; i<1; i+=0.05f) ((+tmp)*=i).display(disp.wait(20));
disp.flush();
for (unsigned long t = 0; !disp.key() && !disp.is_closed(); ++t) {
if (!(t%10)) { if (t%20) disp.display(tmp);
else disp.display((+tmp).draw_image(W/2 - 70,H/2 + 50,pressakey,pressakey,1,255)); }
if (disp.wait(20).is_resized()) disp.resize(disp);
}
if (disp.is_keyESC()) disp.flush();
}
// Test collision between players and borders
if (x1<0 || x1>=img.width() || y1<0 || y1>=img.height() ||
img(x1,y1,0)!=background(x1,y1,0) ||
img(x1,y1,1)!=background(x1,y1,1) ||
img(x1,y1,2)!=background(x1,y1,2) ||
((ix1>=0 || iy1>=0) && (img(ix1,iy1,0)!=background(ix1,iy1,0) || // Collision test for turbo mode
img(ix1,iy1,1)!=background(ix1,iy1,1) ||
img(ix1,iy1,2)!=background(ix1,iy1,2)))) { round_over=1; score2++; }
if (twoplayers) {
if (x2<0 || x2>=img.width() || y2<0 || y2>=img.height() ||
img(x2,y2,0)!=background(x2,y2,0) ||
img(x2,y2,1)!=background(x2,y2,1) ||
img(x2,y2,2)!=background(x2,y2,2) ||
((ix2>=0 || iy2>=0) && (img(ix2,iy2,0)!=background(ix2,iy2,0) || // Collision test for turbo mode
img(ix2,iy2,1)!=background(ix2,iy2,1) ||
img(ix2,iy2,2)!=background(ix2,iy2,2)))) { round_over=2; score1++; }
}
// Draw new players positions
img.draw_point(x1,y1,blue);
if (ix1>=0 && iy1>=0) img.draw_point(ix1,iy1,blue);
if (twoplayers) {
img.draw_point(x2,y2,red);
if (ix2>=0 && iy2>=0) img.draw_point(ix2,iy2,red);
}
if (disp.is_resized()) disp.resize(disp);
img.display(disp);
// Update players positions
x1+=u1; y1+=v1;
if (turbo1) { ix1 = x1; iy1 = y1; x1+=u1; y1+=v1; } else { ix1 = iy1 = -1; }
if (twoplayers) {
x2+=u2; y2+=v2;
if (turbo2) { ix2 = x2; iy2 = y2; x2+=u2; y2+=v2; } else { ix2 = iy2 = -1; }
}
// Test keyboard events
int nu1 = u1, nv1 = v1, nu2 = u2, nv2 = v2;
if (disp.is_keyARROWLEFT()) { nu1 = -1; nv1 = 0; }
if (disp.is_keyARROWRIGHT()) { nu1 = 1; nv1 = 0; }
if (disp.is_keyARROWUP()) { nu1 = 0; nv1 = -1; }
if (disp.is_keyARROWDOWN()) { nu1 = 0; nv1 = 1; }
turbo1 = disp.is_keyCTRLRIGHT();
if (twoplayers) {
if (disp.is_keyQ()) { nu2 = -1; nv2 = 0; }
if (disp.is_keyD()) { nu2 = 1; nv2 = 0; }
if (disp.is_keyZ()) { nu2 = 0; nv2 = -1; }
if (disp.is_keyS()) { nu2 = 0; nv2 = 1; }
turbo2 = disp.is_keyTAB();
}
if (nu1!=-u1 && nv1!=-v1) { u1 = nu1; v1 = nv1; }
if (nu2!=-u2 && nv2!=-v2) { u2 = nu2; v2 = nv2; }
// Check if round is over.
if (round_over) {
const int xc = round_over==1?x1:x2, yc = round_over==1?y1:y2;
for (int r=0; r<50; r+=3) img.draw_circle(xc,yc,r,round_over==1?blue:red,r/300.0f).display(disp.wait(20));
for (int rr=0; rr<50; rr+=3)
((+img)*=(50 - rr)/50.0f).draw_circle(xc,yc,(50 + rr),round_over==1?blue:red,1/6.0f).display(disp.wait(20));
start_round = true;
}
// Wait a small amount of time
disp.wait(delay);
}
return 0;
}

133
examples/tutorial.cpp Normal file
View file

@ -0,0 +1,133 @@
/*
#
# File : tutorial.cpp
# ( C++ source file )
#
# Description : View the color profile of an image, along the X-axis.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
// Include CImg library file and use its main namespace
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main(int argc,char **argv) {
// Define program usage and read command line parameters
//-------------------------------------------------------
// Display program usage, when invoked from the command line with option '-h'.
cimg_usage("View the color profile of an image along the X axis");
// Read image filename from the command line (or set it to "img/parrot.ppm" if option '-i' is not provided).
const char* file_i = cimg_option("-i",cimg_imagepath "parrot.ppm","Input image");
// Read pre-blurring variance from the command line (or set it to 1.0 if option '-blur' is not provided).
const double sigma = cimg_option("-blur",1.0,"Variance of gaussian pre-blurring");
// Init variables
//----------------
// Load an image, transform it to a color image (if necessary) and blur it with the standard deviation sigma.
const CImg<unsigned char> image = CImg<>(file_i).normalize(0,255).blur((float)sigma).resize(-100,-100,1,3);
// Create two display window, one for the image, the other for the color profile.
CImgDisplay
main_disp(image,"Color image (Try to move mouse pointer over)",0),
draw_disp(500,400,"Color profile of the X-axis",0);
// Define colors used to plot the profile, and a hatch to draw the vertical line
unsigned int hatch = 0xF0F0F0F0;
const unsigned char
red[] = { 255,0,0 },
green[] = { 0,255,0 },
blue [] = { 0,0,255 },
black[] = { 0,0,0 };
// Enter event loop. This loop ends when one of the two display window is closed or
// when the keys 'ESC' or 'Q' are pressed.
while (!main_disp.is_closed() && !draw_disp.is_closed() &&
!main_disp.is_keyESC() && !draw_disp.is_keyESC() && !main_disp.is_keyQ() && !draw_disp.is_keyQ()) {
// Handle display window resizing (if any)
if (main_disp.is_resized()) main_disp.resize().display(image);
draw_disp.resize();
if (main_disp.mouse_x()>=0 && main_disp.mouse_y()>=0) { // Mouse pointer is over the image
const int
xm = main_disp.mouse_x(), // X-coordinate of the mouse pointer over the image
ym = main_disp.mouse_y(), // Y-coordinate of the mouse pointer over the image
xl = xm*draw_disp.width()/main_disp.width(), // Corresponding X-coordinate of the hatched line
x = xm*image.width()/main_disp.width(), // Corresponding X-coordinate of the pointed pixel in the image
y = ym*image.height()/main_disp.height(); // Corresponding Y-coordinate of the pointex pixel in the image
// Retrieve color component values at pixel (x,y)
const unsigned int
val_red = image(x,y,0),
val_green = image(x,y,1),
val_blue = image(x,y,2);
// Create and display the image of the intensity profile
CImg<unsigned char>(draw_disp.width(),draw_disp.height(),1,3,255).
draw_grid(-50*100.0f/image.width(),-50*100.0f/256,0,0,false,true,black,0.2f,0xCCCCCCCC,0xCCCCCCCC).
draw_axes(0,image.width() - 1.0f,255.0f,0.0f,black).
draw_graph(image.get_shared_row(y,0,0),red,1,1,0,255,1).
draw_graph(image.get_shared_row(y,0,1),green,1,1,0,255,1).
draw_graph(image.get_shared_row(y,0,2),blue,1,1,0,255,1).
draw_text(30,5,"Pixel (%d,%d)={%d %d %d}",black,0,1,16,
main_disp.mouse_x(),main_disp.mouse_y(),val_red,val_green,val_blue).
draw_line(xl,0,xl,draw_disp.height() - 1,black,0.5f,hatch=cimg::rol(hatch)).
display(draw_disp);
} else
// else display a text in the profile display window.
CImg<unsigned char>(draw_disp.width(),draw_disp.height()).fill(255).
draw_text(draw_disp.width()/2 - 130,draw_disp.height()/2 - 5,"Mouse pointer is outside the image",
black,0,1,16).display(draw_disp);
// Temporize event loop
cimg::wait(20);
}
return 0;
}

138
examples/use_RGBclass.cpp Normal file
View file

@ -0,0 +1,138 @@
/*
#
# File : use_RGBclass.cpp
# ( C++ source file )
#
# Description : A small code that shows how to write a CImg plugin to
# handle color image manipulation using a user-defined RGB
# class, instead of using classical pixel access of CImg<T>
# with operator().
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : David Tschumperlé
# ( http://tschumperle.users.greyc.fr/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#ifndef cimg_plugin
#define cimg_plugin "examples/use_RGBclass.cpp" // Path of the plugin is relative to the CImg.h file
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main() {
// Load images.
CImg<short> img1(cimg_imagepath "milla.bmp");
const CImg<float> img2 = CImg<float>(cimg_imagepath "parrot.ppm").resize(img1,3);
const float default_color[] = { 30,30,80 };
// Modify 'img1' using the RGB pixel accessor.
cimg_forXY(img1,x,y)
if (!((x*y)%31)) img1.RGB_at(x,y) = default_color;
else if ((x+y)%2) img1.RGB_at(x,y) = img2.RGB_at(x,y);
img1.display();
// Quit.
return 0;
}
#else
//-------------------------
// Start of the plugin code
//-------------------------
// Define a simple structure of *references* to R,G,B values.
//-----------------------------------------------------------
// (Feel free to add your own operators in there !)
struct st_RGB {
T _R,_G,_B,&R,&G,&B;
// Construct from R,G,B references of values.
st_RGB(const T& nR, const T& nG, const T& nB):_R(nR),_G(nG),_B(nB),R(_R),G(_G),B(_B) {}
st_RGB(T& nR, T& nG, T& nB):R(nR),G(nG),B(nB) {}
// Copy constructors.
st_RGB(const st_RGB& rgb):_R(rgb.R),_G(rgb.G),_B(rgb.B),R(_R),G(_G),B(_B) {}
template<typename t>
st_RGB(const t& rgb):_R(rgb[0]),_G(rgb[1]),_B(rgb[2]) {}
// Assignement operator.
st_RGB& operator=(const st_RGB& rgb) {
R = (T)(rgb[0]); G = (T)(rgb[1]); B = (T)(rgb[2]);
return *this;
}
template<typename t>
st_RGB& operator=(const t& rgb) {
R = (T)(rgb[0]); G = (T)(rgb[1]); B = (T)(rgb[2]);
return *this;
}
// Data (R,G or B) access operator.
const T& operator[](const unsigned int i) const {
return i==2?B:(i==1?G:R);
}
T& operator[](const unsigned int i) {
return i==2?B:(i==1?G:R);
}
// Print instance on the standard error.
const st_RGB& print() const {
std::fprintf(stderr,"{ %d %d %d }\n",(int)R,(int)G,(int)B);
return *this;
}
};
// Define CImg<T> member functions which return pixel values as st_RGB instances.
//--------------------------------------------------------------------------------
const st_RGB RGB_at(const int x, const int y=0, const int z=0) const {
const int whz = width()*height()*depth();
const T *const pR = data() + x + y*width() + z*width()*height(), *const pG = pR + whz, *const pB = pG + whz;
return st_RGB(*pR,*pG,*pB);
}
st_RGB RGB_at(const int x, const int y=0, const int z=0) {
const int whz = width()*height()*depth();
T *const pR = data() + x + y*width() + z*width()*height(), *const pG = pR + whz, *const pB = pG + whz;
return st_RGB(*pR,*pG,*pB);
}
//------------------------
// End of the plugin code
//------------------------
#endif

70
examples/use_chlpca.cpp Normal file
View file

@ -0,0 +1,70 @@
/*
#
# File : use_chlpca.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/chlpca.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Jerome Boulanger
# ( http://www.irisa.fr/vista/Equipe/People/Jerome.Boulanger.html )
#
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#define cimg_plugin "plugins/chlpca.h"
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main(int argc,char **argv) {
cimg_usage("Patch based denoising ");
const char *file_i = cimg_option("-i",cimg_imagepath "milla.bmp","Input image");
const int p = cimg_option("-p",3,"patch radius");
const int w = cimg_option("-w",10,"window radius");
const float lambda_min = cimg_option("-l",(float)2.f,"component selection threshold");
const int nstep = cimg_option("-nstep",5,"sub-sampling");
const float nsim = cimg_option("-nsim",(float)5.f,"dictionnary size a multiple of the patch size");
const float noise_std = cimg_option("-sigma",(float)-1.f,"noise std (-1:estimated)");
const bool use_svd = cimg_option("-svd",(float)-1.f,"use svd for computing PCA");
const char *file_o = cimg_option("-o",(char*)NULL,"Output file");
CImg<> img(file_i);
img = img.get_chlpca(p, w, nstep, nsim, lambda_min, noise_std, use_svd);
img.display();
if (file_o) img.save(file_o);
return 0;
}

155
examples/use_cimgIPL.cpp Normal file
View file

@ -0,0 +1,155 @@
/*
#
# File : use_cimgIPL.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/cimgIPL.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : newleft (haibo.zheng@gmail.com)
# newleftist@hotmail.com
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include <cv.h>
#include <highgui.h>
#include <math.h>
#pragma comment(lib, "cv.lib")
#pragma comment(lib, "cvaux.lib")
#pragma comment(lib, "cxcore.lib")
#pragma comment(lib, "highgui.lib")
#define cimg_plugin1 "plugins\cimgIPL.h"
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main(int argc, char* argv[]) {
int wid = 0;
CImg<> cImg(argv[1]);
cImg.display("cImg");
IplImage* ipl;
//ipl = cvLoadImage(argv[1], -1);
ipl = cImg.get_IPL();
IplImage *ipl8;
IplImage *ipl16, *ipl32, *ipl64;
IplImage *ipl16to8, *ipl32to8, *ipl64to8;
cvNamedWindow("origin", wid++);
cvNamedWindow("8bit_OK", wid++);
cvNamedWindow("16bit", wid++);
cvNamedWindow("32bit", wid++);
cvNamedWindow("64bit", wid++);
cvNamedWindow("16bitto8", wid++);
cvNamedWindow("32bitto8", wid++);
cvNamedWindow("64bitto8", wid++);
cvShowImage("origin", ipl);
ipl8 = cvCreateImage(cvGetSize(ipl), IPL_DEPTH_8U, ipl->nChannels);
cvConvert(ipl, ipl8);
ipl16 = cvCreateImage(cvGetSize(ipl), IPL_DEPTH_16U, ipl->nChannels);
cvConvert(ipl, ipl16);
ipl32 = cvCreateImage(cvGetSize(ipl), IPL_DEPTH_32F, ipl->nChannels);
cvConvert(ipl, ipl32);
ipl64 = cvCreateImage(cvGetSize(ipl), IPL_DEPTH_64F, ipl->nChannels);
cvConvert(ipl, ipl64);
cvShowImage("8bit_OK", ipl8);// this canbe show properly
cvShowImage("16bit", ipl16);// maynot display properly, that's bug of cvShowImage
cvShowImage("32bit", ipl32);// maynot display properly, that's bug of cvShowImage
cvShowImage("64bit", ipl64);// maynot display properly, that's bug of cvShowImage
// cvShowImage can only display IplImage with IPL_DEPTH_8X, proved by the following codes
ipl16to8 = cvCreateImage(cvGetSize(ipl16), IPL_DEPTH_8U, ipl16->nChannels);
cvConvert(ipl16, ipl16to8);
ipl32to8 = cvCreateImage(cvGetSize(ipl32), IPL_DEPTH_8U, ipl32->nChannels);
cvConvert(ipl32, ipl32to8);
ipl64to8 = cvCreateImage(cvGetSize(ipl64), IPL_DEPTH_8U, ipl64->nChannels);
cvConvert(ipl64, ipl64to8);
cvShowImage("16bitto8", ipl16to8); // diplay ok
cvShowImage("32bitto8", ipl32to8); // diplay ok
cvShowImage("64bitto8", ipl64to8); // diplay ok
// now, we test ipl8->cImg, ipl16->cImg, ipl32->cImg, ipl64->cImg
cImg.assign(ipl8);
cImg.display("ipl8->cimg");
cImg.assign(ipl16);
cImg.display("ipl16->cimg");
cImg.assign(ipl32);
cImg.display("ipl32->cimg");
cImg.assign(ipl64);
cImg.display("ipl64->cimg");
cvWaitKey(0);
// test another construct
CImg<unsigned char> testCImg1(ipl16);
testCImg1.display("testCImg1");
CImg<unsigned char> testCImg2(ipl32);
testCImg2.display("testCImg2");
CImg<unsigned char> testCImg3(ipl64);
testCImg3.display("testCImg3");
CImg<double> testCImg4(ipl16);
testCImg4.display("testCImg4");
CImg<double> testCImg5(ipl32);
testCImg5.display("testCImg5");
CImg<double> testCImg6(ipl64);
testCImg6.display("testCImg6");
cvReleaseImage(&ipl);
cvReleaseImage(&ipl8);
cvReleaseImage(&ipl16);
cvReleaseImage(&ipl32);
cvReleaseImage(&ipl64);
cvReleaseImage(&ipl16to8);
cvReleaseImage(&ipl32to8);
cvReleaseImage(&ipl64to8);
cvDestroyWindow("origin");
cvDestroyWindow("8bit_OK");
cvDestroyWindow("16bit");
cvDestroyWindow("32bit");
cvDestroyWindow("64bit");
cvDestroyWindow("16bitto8");
cvDestroyWindow("32bitto8");
cvDestroyWindow("64bitto8");
return 0;
}

102
examples/use_cimgmatlab.cpp Normal file
View file

@ -0,0 +1,102 @@
/*-----------------------------------------------------------------------
File : use_cimgmatlab.cpp
Description: Example of use for the CImg plugin 'plugins/cimgmatlab.h'
which allows to use CImg in order to develop matlab external
functions (mex functions).
User should be familiar with Matlab C/C++ mex function concepts,
as this file is by no way a mex programming tutorial.
This simple example implements a mex function that can be called
as
- v = cimgmatlab_cannyderiche(u,s)
- v = cimgmatlab_cannyderiche(u,sx,sy)
- v = cimgmatlab_cannyderiche(u,sx,sy,sz)
The corresponding m-file is cimgmatlab_cannyderiche.m
Copyright : Francois Lauze - http://www.itu.dk/people/francois
This software is governed by the Gnu Lesser General Public License
see http://www.gnu.org/copyleft/lgpl.html
The plugin home page is at
http://www.itu.dk/people/francois/cimgmatlab.html
for the compilation: using the mex utility provided with matlab, just
remember to add the -I flags with paths to CImg.h and/or cimgmatlab.h.
The default lcc cannot be used, it is a C compiler and not a C++ one!
--------------------------------------------------------------------------*/
#include <mex.h>
#define cimg_plugin "plugins/cimgmatlab.h"
#include <CImg.h>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if (nrhs < 2) mexErrMsgTxt("No enough input arguments.");
if (nrhs > 4) mexErrMsgTxt("Too many input arguments.");
cimg_library::CImg<> u(prhs[0],true);
if (nrhs == 2) {
const float s = (float)mxGetScalar(prhs[1]);
plhs[0] = u.get_blur(s).toMatlab();
} else if (nrhs == 3) {
const float sx = (float)mxGetScalar(prhs[1]);
const float sy = (float)mxGetScalar(prhs[2]);
plhs[0] = u.get_blur(sx,sy,0).toMatlab();
} else if (nrhs == 4) {
const float sx = (float)mxGetScalar(prhs[1]);
const float sy = (float)mxGetScalar(prhs[2]);
const float sz = (float)mxGetScalar(prhs[3]);
plhs[0] = u.get_blur(sx,sy,sz).toMatlab();
}
}
/*------------------------------------------------------------------
SPECIAL NOTE :
-------------
How to read a .mat file using plugin 'cimgmatlab.h' ?
(contribution by Vo Duc Khanh/Denso IT Lab, Tokyo, Japan).
#include <mex.h>
#include <mat.h>
#include <matrix.h>
#define cimg_plugin "cimgmatlab.h"
#include "CImg.h"
#include <iostream>
#include <string>
.........
using namespace cimg_library;
using namespace std;
// Load input images (125700 images) from training database 'BmpTrainingDb.mat'
MATFile *pmat, *pmat_out;
mxArray *pa, *pa_out;
const char data_path[256] = ".\\BmpTrainingDb.mat\0";
const char *var_name;
pmat = matOpen(data_path, "r");
if (pmat == NULL) {
cout << "Error opening file " << data_path << endl;
return (1);
}
pa = matGetNextVariable(pmat, &var_name);
if (pa == NULL){
cout << "Error reading in file " << data_path << endl;
return (1);
}
CImg<unsigned char> train_db(pa,false);
........
-----------------------------------------------------------------------------*/

33
examples/use_cimgmatlab.m Normal file
View file

@ -0,0 +1,33 @@
/*-----------------------------------------------------------------------
File : use_cimgmatlab.m
Description: Example of use for the CImg plugin 'plugins/cimgmatlab.h'
which allows to use CImg in order to develop matlab external
functions (mex functions).
User should be familiar with Matlab C/C++ mex function concepts,
as this file is by no way a mex programming tutorial.
This simple example implements a mex function that can be called
as
- v = cimgmatlab_cannyderiche(u,s)
- v = cimgmatlab_cannyderiche(u,sx,sy)
- v = cimgmatlab_cannyderiche(u,sx,sy,sz)
The corresponding m-file is cimgmatlab_cannyderiche.m
Copyright : Francois Lauze - http://www.itu.dk/people/francois
This software is governed by the Gnu General Public License
see http://www.gnu.org/copyleft/gpl.html
The plugin home page is at
http://www.itu.dk/people/francois/cimgmatlab.html
for the compilation: using the mex utility provided with matlab, just
remember to add the -I flags with paths to CImg.h and/or cimgmatlab.h.
The default lcc cannot be used, it is a C compiler and not a C++ one!
--------------------------------------------------------------------------*/
function v = cimgmatlab_cannyderiche(u,sx,sy,sz)

View file

@ -0,0 +1,138 @@
/*
#
# File : use_draw_gradient.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/draw_gradient.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Jerome Boulanger
# ( http://www.ricam.oeaw.ac.at/people/page.cgi?firstn=Jerome;lastn=Boulanger )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#define cimg_plugin "plugins/draw_gradient.h"
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//---------------
int main(int argc,char **argv) {
// Read command line arguments
//----------------------------
cimg_usage("Example of the use of draw_gradient CImg plugin");
const char *const file_i = cimg_option("-i",(char*)0,"Input image");
const int shape = cimg_option("-s",1,"shape [0,6]");
const int profile = cimg_option("-p",0,"profile [0,7]");
// Define an image
CImg<unsigned char> img;
if (file_i) img.load(file_i).resize(-100,-100,-100,3);
else img.assign(300,200,1,3,0);
// Define the color of the gradient
CImg<unsigned char> col(3);
const unsigned char col1[3] = { 0,0,255 }, col2[3] = { 255,255,255 };
CImgDisplay disp(img,"Click and drag to create color gradient",0);
while (!disp.is_closed() && !disp.key()) {
// Get a vector direction from the user.
const CImg<int> selection = img.get_select(disp,1);
// Draw a gradient using the selected coordinated.
col.rand(100,255);
printf("Gradient with %s from color (%d,%d,%d) to (%d,%d,%d)\n",
CImg<>::get_gradient_str(shape,profile),col(0),col(1),col(2),col1[0],col1[1],col2[2]);
img.draw_gradient(selection(0),selection(1),selection(3),selection(4),
col.data(),col1,shape,profile,.7f).display(disp);
}
// color 0 to transparency
if (file_i) img.load(file_i).resize(-100,-100,-100,3);
else img.assign(300,200,1,3,0);
img.display(disp);
disp.show().flush();
while (!disp.is_closed() && !disp.key()) {
// Get a vector direction from the user.
const CImg<int> selection = img.get_select(disp,1);
// Draw a gradient using the selected coordinated.
col.rand(100,255);
printf("Gradient with %s from color (%d,%d,%d) to transparency\n",
CImg<>::get_gradient_str(shape,profile),col(0),col(1),col(2));
img.draw_gradient(selection(0),selection(1),selection(3),selection(4),
col.data(),0,shape,profile,.7f).display(disp);
}
// transparency to color 1
if (file_i) img.load(file_i).resize(-100,-100,-100,3);
else img.assign(300,200,1,3,0);
img.display(disp);
disp.show().flush();
while (!disp.is_closed() && !disp.key()) {
// Get a vector direction from the user.
const CImg<int> selection = img.get_select(disp,1);
// Draw a gradient using the selected coordinated.
col.rand(100,255);
printf("Gradient with %s from transparency to color (%d,%d,%d)\n",
CImg<>::get_gradient_str(shape,profile),col(0),col(1),col(2));
img.draw_gradient(selection(0),selection(1),selection(3),selection(4),
0,col.data(),shape,profile,.7f).display(disp);
}
// random
if (file_i) img.load(file_i).resize(-100,-100,-100,3);
else img.assign(300,200,1,3,0);
disp.set_title("Random color gradient").show().flush();
CImg<unsigned char> visu(img);
visu.display(disp);
while (!disp.is_closed() && !disp.key()) {
const int
x = (int)(cimg::rand()*visu.width()),
y = (int)(cimg::rand()*visu.height()),
rx = (int)((cimg::rand()*25 + 5)*(cimg::rand()>.5?-1:1)),
ry = (int)((cimg::rand()*25 + 5)*(cimg::rand()>.5?-1:1));
col.rand(64,255);
img.draw_gradient(x,y,x + rx,y + ry,col.data(),0,shape,profile,.4f);
visu = img;
visu.draw_text(10,10,"%.1ffps",col2,0,1,13,disp.frames_per_second()).display(disp);
if (disp.is_resized()) disp.resize();
}
return 0;
}

View file

@ -0,0 +1,109 @@
/*
#
# File : use_jpeg_buffer.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/jpeg_buffer.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Paolo Prete
# ( p4olo_prete(at)yahoo.it )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
// These includes are necessary to get the plug-in compile !
#include <cstdio>
#include <jpeglib.h>
#include <jerror.h>
// Define plugin and include the CImg Library.
#define cimg_plugin "plugins/jpeg_buffer.h"
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main() {
// Create a jpeg memory buffer from the content of a jpeg file.
// (this is for testing purposes only)
const char *filename_input = "foo.jpg";
std::fprintf(stderr," - Reading file '%s'\n",filename_input);
std::FILE *file_input = std::fopen(filename_input,"rb");
if (!file_input) { std::fprintf(stderr,"Input JPEG file not found !"); std::exit(0); }
std::fprintf(stderr," - Construct input JPEG-coded buffer\n");
unsigned buf_size = 500000; // Put the file size here !
JOCTET *buffer_input = new JOCTET[buf_size];
if (std::fread(buffer_input,sizeof(JOCTET),buf_size,file_input)) std::fclose(file_input);
// -> 'buffer_input' is now a valid jpeg-coded memory buffer.
// Create a CImg instance from the jpeg-coded buffer using the plug-in function.
std::fprintf(stderr," - Create CImg instance from JPEG-coded buffer\n");
CImg<unsigned char> img;
img.load_jpeg_buffer(buffer_input, buf_size);
delete[] buffer_input;
// Do you image processing stuff here ....
// Here, we just mirror the image and write "hello".
std::fprintf(stderr," - Do simple processing\n");
const unsigned char purple[] = { 255, 0, 0 };
const unsigned char black[] = { 0, 0, 0 };
img.mirror('y').draw_text(0,0," Hello! ",purple,black,1,57);
// Display image to see if everything's fine.
img.display("Using 'jpeg_buffer.h' plugin");
// Define a new JOCTET array where the processed image has to be saved
// (we don't know its dimension before compressing it, therefore we have to allocate enough memory )
std::fprintf(stderr," - Construct output JPEG-coded buffer\n");
JOCTET *buffer_output = new JOCTET[2*buf_size];
// Save processed image into this JOCTET buffer, compressed as jpeg.
// This is done again by using the plug-in function.
img.save_jpeg_buffer(buffer_output,buf_size,60);
// Note that here, the variable 'buf_size' contains the length of the
// data which have been written in the given output buffer.
// Copy the content of the above array into a new file
// (it should give you a valid JPEG file then !)
const char *filename_output = "foo_output.jpg";
std::fprintf(stderr," - Save output file '%s'\n",filename_output);
std::FILE* file_output = std::fopen(filename_output,"wb");
std::fwrite(buffer_output, sizeof(JOCTET), buf_size, file_output);
std::fclose(file_output);
delete[] buffer_output;
std::fprintf(stderr," - All done !\n");
return 0;
}

125
examples/use_nlmeans.cpp Normal file
View file

@ -0,0 +1,125 @@
/*
#
# File : use_nlmeans.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/nlmeans.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Jerome Boulanger
# ( http://www.irisa.fr/vista/Equipe/People/Jerome.Boulanger.html )
#
# Benchmark : (CPU intel pentium 4 2.60GHz) compiled with cimg_debug=0.
# patch lambda* alpha T sigma PSNR
# 3x3 15 9x9 3.6s 20 28.22
# 5x5 17 15x15 22.2s 20 27.91
# 7x7 42 21x21 80.0s 20 28.68
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#define cimg_plugin "plugins/nlmeans.h"
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main(int argc,char **argv) {
// Read command line argument s
//-----------------------------
cimg_usage("Non-local means denoising algorithm.\n [1] Buades, A. Coll, B. and Morel, J.: A review of image "
"denoising algorithms, with a new one. Multiscale Modeling and Simulation: A SIAM Interdisciplinary "
"Journal 4 (2004) 490-530 \n [2] Gasser, T. Sroka,L. Jennen Steinmetz,C. Residual variance and residual "
"pattern nonlinear regression. Biometrika 73 (1986) 625-659 \n Build : ");
// input/output and general options
const char *file_i = cimg_option("-i",cimg_imagepath "milla.bmp","Input image");
const char *file_o = cimg_option("-o",(char*)NULL,"Output file");
const double zoom = cimg_option("-zoom",1.0,"Image magnification");
const double noiseg = cimg_option("-ng",0.0,"Add gauss noise before aplying the algorithm");
const double noiseu = cimg_option("-nu",0.0,"Add uniform noise before applying the algorithm");
const double noises = cimg_option("-ns",0.0,"Add salt&pepper noise before applying the algorithm");
const unsigned int visu = cimg_option("-visu",1,"Visualization step (0=no visualization)");
// non local means options
const int patch_size = cimg_option("-p",1,"Half size of the patch (2p+1)x(2p+1)");
const float lambda = (float)cimg_option("-lambda",-1.0f,"Bandwidth as defined in [1] (-1 : automatic bandwidth)");
const double sigma = cimg_option("-sigma",-1,"Noise standard deviation (-1 : robust estimation)");
const int alpha = cimg_option("-alpha",3,"Neighborhood size (3)");
const int sampling = cimg_option("-sampling",1,"Sampling of the patch (1: slow, 2: fast)");
// Read image
//------------
CImg<> img;
if (file_i) {
img = CImg<>(file_i);
if (zoom>1)
img.resize((int)(img.width()*zoom),(int)(img.height()*zoom),(int)(img.depth()*zoom),-100,3);
} else throw CImgException("You need to specify at least one input image (option -i)");
CImg<> original=img;
// Add some noise
//-----------------
img.noise(noiseg,0).noise(noiseu,1).noise(noises,2);
// Apply the filter
//---------------------
cimg_uint64 tic = cimg::time();
CImg<> dest;
dest = img.get_nlmeans(patch_size,lambda,alpha,sigma,sampling);
cimg_uint64 tac = cimg::time();
// Save result
//-----------------
if (file_o) dest.cut(0,255.f).save(file_o);
// Display (option -visu)
//-----------------------
if (visu){
fprintf(stderr,"Image computed in %f s \n",(float)(tac - tic)/1000.);
fprintf(stderr,"The pnsr is %f \n",
20.*std::log10(255./std::sqrt( (dest - original).pow(2).sum()/original.size() )));
if (noiseg==0 && noiseu==0 && noises==0)
CImgList<>(original,dest,((dest - original)*=2)+=128).display("Original + Restored + Estimated Noise");
else {
CImgList<>(original,img,dest,((dest - img)*=2)+=128,((dest - original)*=2)+=128).
display("Original + Noisy + Restored + Estimated Noise + Original Noise");
}
}
return 0;
}

119
examples/use_skeleton.cpp Normal file
View file

@ -0,0 +1,119 @@
/*
#
# File : use_skeleton.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/skeleton.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Francois-Xavier Dupe
# ( http://www.greyc.ensicaen.fr/~fdupe/ )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include <queue>
#define cimg_plugin "plugins/skeleton.h"
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Main procedure
//----------------
int main (int argc, char **argv) {
cimg_usage("Compute the skeleton of a shape, using Hamilton-Jacobi equations");
// Read command line arguments
cimg_help("Input/Output options\n"
"--------------------");
const char* file_i = cimg_option("-i",cimg_imagepath "milla.bmp","Input (black&white) image");
const int median = cimg_option("-median",0,"Apply median filter");
const bool invert = cimg_option("-inv",false,"Invert image values");
const char* file_o = cimg_option("-o",(char*)0,"Output skeleton image");
const bool display = cimg_option("-visu",true,"Display results");
cimg_help("Skeleton computation parameters\n"
"-------------------------------");
const float thresh = cimg_option("-t",-0.3f,"Threshold");
const bool curve = cimg_option("-curve",false,"Create medial curve");
cimg_help("Torsello correction parameters\n"
"------------------------------");
const bool correction = cimg_option("-corr",false,"Torsello correction");
const float dlt1 = 2;
const float dlt2 = cimg_option("-dlt",1.0f,"Discrete step");
// Load the image (forcing it to be scalar with 2 values { 0,1 }).
CImg<unsigned int> image0(file_i), image = image0.get_norm().quantize(2).normalize(0.0f,1.0f).round();
if (median) image.blur_median(median);
if (invert) (image-=1)*=-1;
if (display) (image0.get_normalize(0,255),image.get_normalize(0,255)).display("Input image - Binary image");
// Compute distance map.
CImgList<float> visu;
CImg<float> distance = image.get_distance(0);
if (display) visu.insert(distance);
// Compute the gradient of the distance function, and the flux (divergence) of the gradient field.
const CImgList<float> grad = distance.get_gradient("xyz");
CImg<float> flux = image.get_flux(grad,1,1);
if (display) visu.insert(flux);
// Use the Torsello correction of the flux if necessary.
if (correction) {
CImg<float>
logdensity = image.get_logdensity(distance,grad,flux,dlt1),
nflux = image.get_corrected_flux(logdensity,grad,flux,dlt2);
if (display) visu.insert(logdensity).insert(nflux);
flux = nflux;
}
if (visu) {
cimglist_apply(visu,normalize)(0,255);
visu.display(visu.size()==2?"Distance function - Flux":"Distance function - Flux - Log-density - Corrected flux");
}
// Compute the skeleton
const CImg<unsigned int> skel = image.get_skeleton(flux,distance,curve,thresh);
if (display) {
(image0.resize(-100,-100,1,3)*=0.7f).get_shared_channel(1)|=skel*255.0;
image0.draw_image(0,0,0,0,image*255.0,0.5f).display("Image + Skeleton");
}
// Save output image if necessary.
if (file_o) skel.save(file_o);
return 0;
}

View file

@ -0,0 +1,81 @@
/*
#
# File : use_tiff_stream.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/jpeg_buffer.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Wolf Blecher
# ( Wolf.Blecher(at)sirona.com )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include <fstream>
// These includes are necessary to get the plug-in compile ! Don't forget to link with 'libtiff' and 'libtiffxx' !
#include "tiffio.h"
#include "tiffio.hxx"
// Define plugin and include the CImg Library.
#define cimg_plugin "plugins/tiff_stream.h"
#include "CImg.h"
using namespace cimg_library;
// Main procedure
//----------------
int main() {
std::ifstream inFile("input.tif", std::ifstream::in | std::ifstream::binary);
std::ofstream outFile("outFile.tif", std::ofstream::out | std::ifstream::binary);
if (!inFile.good())
{
std::cout << "Error Reading from infile" << std::endl;
}
cimg_library::CImg<unsigned short> imgIn;
imgIn.load_tiff(&inFile);
imgIn.display();
CImg<unsigned short> imgOut = imgIn.save_tiff(&outFile, 2U);
imgOut.display();
inFile.close();
outFile.close();
inFile.open("outFile.tif", std::ifstream::in | std::ifstream::binary);
imgIn.load_tiff(&inFile);
imgIn.display();
inFile.close();
return 0;
}

View file

@ -0,0 +1,135 @@
/*
#
# File : use_tinymatwriter.cpp
# ( C++ source file )
#
# Description : Example of use for the CImg plugin 'plugins/tinymatwriter.h'.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Copyright : Jan W. Krieger
# ( https://github.com/jkriege2 )
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
/*
This Matlab/Octave script tests the output:
clear all
more off
subplot(2,2,1)
load("mat432.mat", "-v6")
disp('mat432.mat: CImg_image=')
disp(CImg_image)
imagesc(CImg_image(:,:,1))
colorbar
subplot(2,2,2)
load("mat432i16.mat", "-v6")
disp('mat432i16.mat: CImg_image=')
disp(CImg_image)
imagesc(double(CImg_image(:,:,2)))
colorbar
subplot(2,2,3)
load("matb.mat", "-v6")
disp('matb.mat: CImg_image=')
disp(CImg_image)
imagesc(CImg_image(:,:,4))
colorbar
*/
#include <iostream>
#include <stdio.h>
#include "tinymatwriter.h"
#include <cmath>
#define cimg_plugin "plugins/tinymatwriter.h"
#include "../CImg.h"
using namespace std;
using namespace cimg_library;
int main(int argc, const char** argv) {
double mat432[4*3*2]= {
1,2,3,
4,5,6,
10,20,30,
40,50,60,
100,200,300,
400,500,600,
1000,2000,3000,
4000,5000,6000,
};
int16_t mat432i16[4*3*2]= {
1,2,3,
4,5,6,
10,20,30,
40,50,60,
100,200,300,
400,500,600,
1000,-2000,3000,
-4000,5000,-6000,
};
// a boolean matrix
bool matb[4*3*2] = {
true,false,true,
false,true,false,
true,true,true,
false,false,false,
true,false,true,
true,false,true,
true,true,false,
false,true,true
};
cimg_library::CImg<double> ciD(mat432, 3,2,4);
cimg_library::CImg<int16_t> ciI16(mat432i16, 3,2,4);
cimg_library::CImg<bool> ciB(matb, 3,2,4);
ciD.save_tinymat("mat432.mat");
ciI16.save_tinymat("mat432i16.mat");
ciB.save_tinymat("matb.mat");
return 0;
}

191
examples/wavelet_atrous.cpp Normal file
View file

@ -0,0 +1,191 @@
/*
#
# File : wavelet_atrous.cpp
# ( C++ source file )
#
# Description : Performs a 2D or 3D 'a trous' wavelet transform
# (using a cubic spline) on an image or a video sequence.
# This file is a part of the CImg Library project.
# ( http://cimg.eu )
#
# Author : Renaud Peteri
# ( Renaud.Peteri(at)mines-paris.org )
# Andrea Onofri
# ( Andrea.Onofri(at)teletu.it )
#
# Institution : CWI, Amsterdam
#
# Date : February 2005
#
# References : Starck, J.-L., Murtagh, F. and Bijaoui, A.,
# Image Processing and Data Analysis: The Multiscale Approach,
# Cambridge University Press, 1998.
# (Hardback and softback, ISBN 0-521-59084-1 and 0-521-59914-8.)
#
# License : CeCILL v2.0
# ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
#
# This software is governed by the CeCILL license under French law and
# abiding by the rules of distribution of free software. You can use,
# modify and/ or redistribute the software under the terms of the CeCILL
# license as circulated by CEA, CNRS and INRIA at the following URL
# "http://www.cecill.info".
#
# As a counterpart to the access to the source code and rights to copy,
# modify and redistribute granted by the license, users are provided only
# with a limited warranty and the software's author, the holder of the
# economic rights, and the successive licensors have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading, using, modifying and/or developing or reproducing the
# software by the user in light of its specific status of free software,
# that may mean that it is complicated to manipulate, and that also
# therefore means that it is reserved for developers and experienced
# professionals having in-depth computer knowledge. Users are therefore
# encouraged to load and test the software's suitability as regards their
# requirements in conditions enabling the security of their systems and/or
# data to be ensured and, more generally, to use and operate it in the
# same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
#
*/
#include "CImg.h"
using namespace cimg_library;
#ifndef cimg_imagepath
#define cimg_imagepath "img/"
#endif
// Define convolution mask.
CImg<float> mask(const unsigned char dirIdx, const unsigned char scale) {
const int
d1 = 1 << (scale-1),
d2 = 1 << scale,
c = d2,
vecLen = (1 << (scale + 1)) + 1;
const float
valC = 0.375f, // 6/16
valD1 = 0.25f, // 4/16
valD2 = 0.0625f; // 1/16
switch(dirIdx) {
case 0 : { // x
CImg<float> m(vecLen,1,1,1,0);
m(c) = valC;
m(c - d1) = m(c + d1) = valD1;
m(c - d2) = m(c + d2) = valD2;
return m;
}
case 1: { // y
CImg<float> m(1,vecLen,1,1,0);
m(0,c) = valC;
m(0,c - d1) = m(0,c + d1) = valD1;
m(0,c - d2) = m(0,c + d2) = valD2;
return m;
}
case 2: { // t
CImg<float> m(1,1,vecLen,1,0);
m(0,0,c) = valC;
m(0,0,c - d1) = m(0,0,c + d1) = valD1;
m(0,0,c - d2) = m(0,0,c + d2) = valD2;
return m;
}
default: throw CImgException("Error, unknow decompostion axe, dirIdx = '%c'.",dirIdx);
}
}
/*------------------
Main procedure
----------------*/
int main(int argc,char **argv) {
cimg_usage("Perform an 'a trous' wavelet transform (using a cubic spline) on an image or on a video sequence.\n"
"This wavelet transform is undecimated and produces 2 images/videos at each scale. For an example of\n"
"decomposition on a video, try -i img/trees.inr (sequence from the MIT).\n"
"\t(Type -h for help)");
// Read command line parameters
const char
*name_i = cimg_option("-i",cimg_imagepath "parrot.ppm","Input image or video"),
*name_o = cimg_option("-o","","Name of the multiscale analysis output"),
*axe_dec = cimg_option("-axe",(char*)0,
"Perform the multiscale decomposition in just one direction ('x', 'y' or 't')");
const unsigned int
s = cimg_option("-s",3,"Scale of decomposition");
const bool help = cimg_option("-h",false,"Display Help");
if (help) std::exit(0);
// Initialize Image Data
std::fprintf(stderr," - Load image sequence '%s'...\n",cimg::basename(name_i));
const CImg<float> texture_in(name_i);
CImg<float> mask_conv;
CImgList<float> res(s,texture_in.width(),texture_in.height(),texture_in.depth());
CImgList<float> wav(s,texture_in.width(),texture_in.height(),texture_in.depth());
cimglist_for(res,l) { res(l).fill(0.0); wav(l).fill(0.0); }
unsigned int i;
int firstDirIdx = 0,lastDirIdx = 2;
if (axe_dec) { // The multiscale decomposition will be performed in just one direction
char c = cimg::lowercase(axe_dec[0]);
switch(c) {
case 'x': firstDirIdx = 0; break;
case 'y': firstDirIdx = 1; break;
case 't': firstDirIdx = 2; break;
default: throw CImgException("Error, unknow decompostion axe '%c', try 'x', 'y' or 't'",c);
}
lastDirIdx = firstDirIdx; // Only one direction
}
for (i = 0; i<s; i++) {
std::fprintf(stderr," - Performing scale %u ...\n",i + 1);
if (i==0) { res(i) = texture_in;} else { res(i) = res(i - 1); }
for (int di = firstDirIdx; di<=lastDirIdx; di++) {
mask_conv = mask((unsigned char)di,(unsigned char)(i + 1));
res(i) = res(i).get_convolve(mask_conv);
}
if (i==0) { wav(i) = texture_in - res(i); } // res(0) and wav(0) are the 1st scale of decompostion
else { wav(i) = res(i - 1) - res(i); }
}
if (*name_o) {
// Save the Multi-Scale Analysis.
std::fprintf(stderr," - Saving of all output sequences : %s in the msa/ directory... \n",cimg::basename(name_o));
int count = 1; // res0 = original image
char filename[256] = "", filename_wav[256] = "";
char STmp[16] = "";
const int err = std::system("mkdir msa");
if (!err) for (i = 0; i<s; i++) {
std::strcpy( filename, "msa/res" );
std::strcpy( filename_wav, "msa/wav" );
if (count<10) { std::strcat( filename, "0" ); std::strcat( filename_wav, "0" ); }
std::sprintf(STmp,"%d_",count);
std::strcat(filename,STmp); std::strcat(filename_wav,STmp);
std::strcat(filename,name_o); std::strcat(filename_wav,name_o);
res(i).save(filename);
wav(i).save(filename_wav);
count++;
}
}
// Result visualization.
const float col[] = { 255, 255, 255 };
for (i = 0; i<s; i++) {
res[i].normalize(0,255).draw_text(2,2,"Scale %d",col,0,1,13,i);
wav[i].normalize(0,255).draw_text(2,2,"Scale %d",col,0,1,13,i);
}
CImgDisplay disp(res,"Approximations levels by increasing scale",0);
CImgDisplay disp2(wav,"Wavelet coefficients by increasing scale",0);
while (!disp.is_closed() && !disp.is_keyQ() && !disp.is_keyESC() &&
!disp2.is_closed() && !disp2.is_keyQ() && !disp2.is_keyESC()) {
if (disp.is_resized()) disp.resize().display(res);
if (disp2.is_resized()) disp2.resize().display(wav);
CImgDisplay::wait(disp,disp2);
}
return 0;
}

1473
html/CImg.doxygen Normal file

File diff suppressed because it is too large Load diff

1019
html/CImg_documentation.h Normal file

File diff suppressed because it is too large Load diff

2165
html/CImg_flyer.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

63
html/download.html Normal file
View file

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="highslide/highslide.css"/>
<title>The CImg Library - C++ Template Image Processing Toolkit - Download</title>
<script src="jquery-3.5.1.min.js"></script>
<script>var jQuery_3_5_1 = $.noConflict(true);</script>
<script>jQuery_3_5_1(function(){ jQuery_3_5_1("#include_header").load("header.html"); });</script>
<script>jQuery_3_5_1(function(){ jQuery_3_5_1("#include_footer").load("footer.html"); });</script>
<style>
table tr td { padding: 1em; }
</style>
</head>
<body>
<div id="include_header"></div>
<!-- ************* -->
<!-- Download -->
<!-- ************* -->
<div class="section_title"><p>Download</p></div><div class="section_content">
<p>
You have different ways to get the <span class="gmd_cimg"></span> Library:
</p>
<table class="table_content">
<tr><td><a href="http://cimg.eu/files/CImg_latest.zip">
<img src="img/item_standard_package.jpg" alt="Standard Package"
onmouseover="this.src='img/item_standard_package2.jpg';"
onmouseout="this.src='img/item_standard_package.jpg';" /></a></td>
<td><hr/>
The <span class="gmd_cimg"></span> Library is mainly provided as
<a href="http://cimg.eu/files/CImg_latest.zip">
<i>.zip</i> package</a>
which is <b>platform-independent</b>.
It contains all the required files, as well as various examples (which must be compiled),
illustrating the use of the library functions and classes.<br/>
</td></tr>
<tr><td><a href="https://github.com/dtschump/CImg">
<img src="img/item_sources.jpg" alt="Sources Repository"
onmouseover="this.src='img/item_sources2.jpg';"
onmouseout="this.src='img/item_sources.jpg';" /></a></td>
<td><hr/>
You may be also more adventurous and try the current development version with <a href="http://git-scm.com/"><b>git</b></a>.
This ensures you will get the latest code available, and will ease the
updates as well. To do this, just
type the command :
<div class="gmd_code">
<a href="https://github.com/dtschump/CImg">git clone --depth=1 https://github.com/dtschump/CImg.git</a>
</div>
in your favorite console. Nevertheless, you have to know that some code in the source repository
is under development and may be experimental, so always test the latest stable archive before complaining !
</td>
</table>
</div><div class="section_end"></div>
<div id="include_footer"></div>
</body>

BIN
html/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
html/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 520 B

27
html/footer.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
<title>The CImg Library - C++ Template Image Processing Toolkit</title>
</head>
<body>
<div class="bloc_start"></div><div class="bloc_content">
<p style="text-align:center;">
Copyrights (C) From october 2004, David Tschumperlé - GREYC UMR CNRS 6072, Image team.<br/>
Copyrights (C) January->September 2004, David Tschumperlé.<br/>
Copyrights (C) 2000->2003, David Tschumperlé - INRIA Sophia-Antipolis. Odyssée group.<br/>
</p>
</div><div class="bloc_end"></div>
<!-- Default Statcounter code for CImg http://cimg.eu -->
<script>
var sc_project=895001;
var sc_invisible=1;
var sc_security="5ea85181";
</script>
<script src="https://www.statcounter.com/counter/counter.js" async></script>
<noscript><div class="statcounter"><a title="Web Analytics" href="https://statcounter.com/" target="_blank"><img class="statcounter" src="https://c.statcounter.com/895001/0/5ea85181/1/" alt="Web Analytics"></a></div></noscript>
<!-- End of Statcounter Code -->
</body>

22
html/footer_doxygen.html Normal file
View file

@ -0,0 +1,22 @@
</div><div class="section_end"></div>
<div class="bloc_start"></div><div class="bloc_content">
<p style="text-align:center;">
Copyrights (C) From october 2004, David Tschumperlé - GREYC UMR CNRS 6072, Image team.<br/>
Copyrights (C) January->September 2004, David Tschumperlé.<br/>
Copyrights (C) 2000->2003, David Tschumperlé - INRIA Sophia-Antipolis. Odyssée group.<br/>
</p>
</div><div class="bloc_end"></div>
<!-- Default Statcounter code for CImg http://cimg.eu -->
<script>
var sc_project=895001;
var sc_invisible=1;
var sc_security="5ea85181";
</script>
<script src="https://www.statcounter.com/counter/counter.js" async></script>
<noscript><div class="statcounter"><a title="Web Analytics" href="https://statcounter.com/" target="_blank"><img class="statcounter" src="https://c.statcounter.com/895001/0/5ea85181/1/" alt="Web Analytics"></a></div></noscript>
<!-- End of Statcounter Code -->
</body>

68
html/header.html Normal file
View file

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>The CImg Library - C++ Template Image Processing Toolkit</title>
<meta charset="utf-8">
<meta name="author" content="David Tschumperlé">
<meta name="description" content="A full-featured open-source framework for processing generic image (2D,3D,3D+t) with multiple interfaces: command-line (cli), gimp plug-in, web service, Qt plug-in, C++ library">
<meta name="keywords" content="open-source, image processing, command-line tool, GIMP plug-in, Krita plug-in, Paint.NET plug-in, C++ library, ZArt">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" href="style.css">
<!-- Begin Cookie Consent plugin by Silktide - http://silktide.com/cookieconsent -->
<script>
window.cookieconsent_options = {"message":"This website uses cookies to ensure you get the best experience on our website","dismiss":"Got it!","learnMore":"More info","link":null,"theme":"dark-bottom"};
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/1.0.9/cookieconsent.min.js"></script>
<!-- End Cookie Consent plugin -->
</head>
<body>
<!-- Logo and caption -->
<div class="header">
<a href="index.html"><img alt="Logo" src="img/logo_header.jpg" class="center_image" style="margin-top:1em;"/></a>
<h2 style="padding-bottom: 1em">
Latest stable version: <b><a href="http://cimg.eu/files/CImg_2.9.6.zip">2.9.6</a></b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Current pre-release: <b><a href="http://cimg.eu/files/CImg_latest.zip">2.9.7</a></b>
</h2>
<hr/>
<!-- Menu bar -->
<div id='cssmenu'>
<ul>
<li><a href='index.html'><span>
<img alt="Home" src='img/menu_home.png' />&nbsp;&nbsp;
Home</span></a></li>
<li><a href='download.html'><span>
<img alt="Download" src='img/menu_download.png' />&nbsp;&nbsp;
Download</span></a></li>
<li><a href='screenshots.html'><span>
<img alt="Screenshots" src='img/menu_screenshots.png' />&nbsp;&nbsp;
Screenshots</span></a></li>
<!-- <li><a href='reference/faq.html'><span> -->
<!-- <img alt="FAQ" src='img/menu_faq.png' />&nbsp;&nbsp; -->
<!-- FAQ</span></a></li> -->
<li><a href='reference/tutorial.html'><span>
<img alt="Tutorial" src='img/menu_tutorial.png' />&nbsp;&nbsp;
Tutorial</span></a>
<li><a href='reference/'><span>
<img alt="Documentation" src='img/menu_reference.png' />&nbsp;&nbsp;
Documentation</span></a></li>
<li><a href='https://github.com/dtschump/CImg/issues'><span>
<img alt="Report Issue" src='img/menu_issue.png' />&nbsp;&nbsp;
Report Issue</span></a>
<li><a href='links.html'><span>
<img alt="Links" src='img/menu_links.png' />&nbsp;&nbsp;
Links</span></a></li>
<li><a target="_blank" href='https://www.amazon.fr/dp/B08WRCZRR3/ref=cm_sw_em_r_mt_dp_Y4VV7GNQSBQDZ4XQ95YR'><span style="background-color:khaki">
<img alt="Book_fr" src='img/menu_tutorial.png' />&nbsp;&nbsp;
<span style="color: forestgreen">Book (Fr)</span></span></a>
</ul>
</div>
<hr/>
<div style="min-height:1em"></div>
</div>
</body>
</html>

69
html/header_doxygen.html Normal file
View file

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>The CImg Library - C++ Template Image Processing Toolkit - Reference Documentation</title>
<meta charset="utf-8">
<meta name="author" content="David Tschumperlé">
<meta name="description" content="A full-featured open-source framework for processing generic image (2D,3D,3D+t) with multiple interfaces: command-line (cli), gimp plug-in, web service, Qt plug-in, C++ library">
<meta name="keywords" content="open-source, image processing, command-line tool, GIMP plug-in, Krita plug-in, Paint.NET plug-in, C++ library, ZArt">
<link rel="shortcut icon" type="image/x-icon" href="../favicon.ico">
<link rel="icon" type="image/png" href="../favicon.png">
<link rel="stylesheet" href="doxygen.css" type="text/css">
<link rel="stylesheet" href="tabs.css" type="text/css">
<link rel="stylesheet" href="../style.css">
<script src="jquery.js"></script>
<script src="dynsections.js"></script>
<style>
.PageDoc .header { width: 100%; }
.textblock h2, .textblock h1 { color: black; font-weight: bold; font-size: larger; text-align: left; }
.header { width: 100%; }
div.fragment { padding: 1em; }
</style>
</head>
<body>
<!-- Logo and caption -->
<div class="header">
<a href="../index.html"><img alt="Logo" src="../img/logo_header.jpg" class="center_image" style="margin-top:1em;"/></a>
<h2 style="padding-bottom: 1em">
Latest stable version: <b><a href="http://cimg.eu/files/CImg_2.9.6.zip">2.9.6</a></b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Current pre-release: <b><a href="http://cimg.eu/files/CImg_latest.zip">2.9.7</a></b>
</h2>
<hr/>
<!-- Menu bar -->
<div id='cssmenu'>
<ul>
<li><a href='../index.html'><span>
<img alt="Home" src='../img/menu_home.png' />&nbsp;&nbsp;
Home</span></a></li>
<li><a href='../download.html'><span>
<img alt="Download" src='../img/menu_download.png' />&nbsp;&nbsp;
Download</span></a></li>
<li><a href='../screenshots.html'><span>
<img alt="Screenshots" src='../img/menu_screenshots.png' />&nbsp;&nbsp;
Screenshots</span></a></li>
<!-- <li><a href='../reference/faq.html'><span> -->
<!-- <img alt="FAQ" src='../img/menu_faq.png' />&nbsp;&nbsp; -->
<!-- FAQ</span></a></li> -->
<li><a href='../reference/tutorial.html'><span>
<img alt="Tutorial" src='../img/menu_tutorial.png' />&nbsp;&nbsp;
Tutorial</span></a>
<li><a href='../reference/'><span>
<img alt="Documentation" src='../img/menu_reference.png' />&nbsp;&nbsp;
Documentation</span></a></li>
<li><a href='https://github.com/dtschump/CImg/issues'><span>
<img alt="Report Issue" src='../img/menu_issue.png' />&nbsp;&nbsp;
Report Issue</span></a>
<li><a href='../links.html'><span>
<img alt="Links" src='../img/menu_links.png' />&nbsp;&nbsp;
Links</span></a></li>
<li><a target="_blank" href='https://www.amazon.fr/dp/B08WRCZRR3/ref=cm_sw_em_r_mt_dp_Y4VV7GNQSBQDZ4XQ95YR'><span style="background-color:khaki">
<img alt="Book_fr" src='../img/menu_tutorial.png' />&nbsp;&nbsp;
<span style="color: forestgreen">Book (Fr)</span></span></a>
</ul>
</div>
<hr/>
<div style="min-height:1em"></div>
<div class="section_title"><p>Reference</p></div><div class="section_content"><div>

1891
html/highslide.js Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

File diff suppressed because it is too large Load diff

9
html/highslide/highslide-full.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,76 @@
.closebutton {
/* NOTE! This URL is relative to the HTML page, not the CSS */
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
src='../highslide/graphics/close.png', sizingMethod='scale');
background: none;
cursor: hand;
}
/* Viewport fixed hack */
.highslide-viewport {
position: absolute;
left: expression( ( ( ignoreMe1 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' );
top: expression( ( ignoreMe2 = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) + 'px' );
width: expression( ( ( ignoreMe3 = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) ) + 'px' );
height: expression( ( ( ignoreMe4 = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) ) + 'px' );
}
/* Thumbstrip PNG fix */
.highslide-scroll-down, .highslide-scroll-up {
position: relative;
overflow: hidden;
}
.highslide-scroll-down div, .highslide-scroll-up div {
/* NOTE! This URL is relative to the HTML page, not the CSS */
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
src='../highslide/graphics/scrollarrows.png', sizingMethod='scale');
background: none !important;
position: absolute;
cursor: hand;
width: 75px;
height: 75px !important;
}
.highslide-thumbstrip-horizontal .highslide-scroll-down div {
left: -50px;
top: -15px;
}
.highslide-thumbstrip-horizontal .highslide-scroll-up div {
top: -15px;
}
.highslide-thumbstrip-vertical .highslide-scroll-down div {
top: -50px;
}
/* Thumbstrip marker arrow trasparent background fix */
.highslide-thumbstrip .highslide-marker {
border-color: white; /* match the background */
}
.dark .highslide-thumbstrip-horizontal .highslide-marker {
border-color: #111;
}
.highslide-viewport .highslide-marker {
border-color: #333;
}
.highslide-thumbstrip {
float: left;
}
/* Positioning fixes for the control bar */
.text-controls .highslide-controls {
width: 480px;
}
.text-controls a span {
width: 4em;
}
.text-controls .highslide-full-expand a span {
width: 0;
}
.text-controls .highslide-close a span {
width: 0;
}
/* Special */
.in-page .highslide-thumbstrip-horizontal .highslide-marker {
border-bottom: gray;
}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more