diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9e26507462f2d0ff6c2f6c89f38bb0fc5f8c0c39
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,52 @@
+
+cmake_minimum_required(VERSION 2.8)
+
+project(bgs)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CSS_FLAGS} -std=gnu++0x")
+
+find_package(OpenCV REQUIRED)
+
+if(${OpenCV_VERSION} VERSION_LESS 2.3.1)
+  message (FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}")
+endif()
+
+file(GLOB sources FrameProcessor.cpp PreProcessor.cpp VideoAnalysis.cpp  VideoCapture.cpp)
+file(GLOB main Main.cpp)
+file(GLOB demo Demo.cpp)
+
+list(REMOVE_ITEM sources ${demo})
+
+file(GLOB_RECURSE analysis package_analysis/*.cpp)
+file(GLOB_RECURSE bgs package_bgs/*.cpp)
+file(GLOB_RECURSE bgs_include package_bgs/*.h)
+
+# GMG is not available in older OpenCV versions
+if(${OpenCV_VERSION} VERSION_LESS 2.4.3)
+  file(GLOB gmg package_bgs/GMG.cpp)
+  list(REMOVE_ITEM bgs ${gmg})
+endif()
+
+include_directories(${CMAKE_SOURCE_DIR})
+
+add_library(bgs SHARED ${sources} ${bgs} ${analysis})
+target_link_libraries(bgs ${OpenCV_LIBS})
+set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_include})
+
+add_executable(bgs_bin ${main})
+target_link_libraries(bgs_bin ${OpenCV_LIBS} bgs)
+set_target_properties(bgs_bin
+  PROPERTIES OUTPUT_NAME bgs)
+
+add_executable(bgs_demo ${demo})
+target_link_libraries(bgs_demo ${OpenCV_LIBS} bgs)
+
+INSTALL(TARGETS bgs
+	bgs_demo
+	bgs_bin
+  RUNTIME DESTINATION bin COMPONENT app
+  LIBRARY DESTINATION lib COMPONENT runtime
+  ARCHIVE DESTINATION lib COMPONENT runtime
+  PUBLIC_HEADER DESTINATION include/package_bgs COMPONENT dev
+  FRAMEWORK DESTINATION "/Library/Frameworks"
+)
diff --git a/COPYING.txt b/COPYING.txt
new file mode 100644
index 0000000000000000000000000000000000000000..94a9ed024d3859793618152ea559a168bbcbb5e2
--- /dev/null
+++ b/COPYING.txt
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Config.h b/Config.h
new file mode 100644
index 0000000000000000000000000000000000000000..01cf7210a47f3682e5e8010311a4f8fc11b0bedd
--- /dev/null
+++ b/Config.h
@@ -0,0 +1,22 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+const int KEY_REPEAT = 'r';
+const int KEY_SPACE  = 32;
+const int KEY_ESC    = 27;
+const int KEY_ESC2   = 'q';
diff --git a/Demo.cpp b/Demo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3936976268b5f548f0b99a7e96fc1f74ba92c52c
--- /dev/null
+++ b/Demo.cpp
@@ -0,0 +1,182 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "package_bgs/FrameDifferenceBGS.h"
+#include "package_bgs/StaticFrameDifferenceBGS.h"
+#include "package_bgs/WeightedMovingMeanBGS.h"
+#include "package_bgs/WeightedMovingVarianceBGS.h"
+#include "package_bgs/MixtureOfGaussianV1BGS.h"
+#include "package_bgs/MixtureOfGaussianV2BGS.h"
+#include "package_bgs/AdaptiveBackgroundLearning.h"
+#include "package_bgs/AdaptiveSelectiveBackgroundLearning.h"
+
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+#include "package_bgs/GMG.h"
+#endif
+
+#include "package_bgs/dp/DPAdaptiveMedianBGS.h"
+#include "package_bgs/dp/DPGrimsonGMMBGS.h"
+#include "package_bgs/dp/DPZivkovicAGMMBGS.h"
+#include "package_bgs/dp/DPMeanBGS.h"
+#include "package_bgs/dp/DPWrenGABGS.h"
+#include "package_bgs/dp/DPPratiMediodBGS.h"
+#include "package_bgs/dp/DPEigenbackgroundBGS.h"
+#include "package_bgs/dp/DPTextureBGS.h"
+
+#include "package_bgs/tb/T2FGMM_UM.h"
+#include "package_bgs/tb/T2FGMM_UV.h"
+#include "package_bgs/tb/T2FMRF_UM.h"
+#include "package_bgs/tb/T2FMRF_UV.h"
+#include "package_bgs/tb/FuzzySugenoIntegral.h"
+#include "package_bgs/tb/FuzzyChoquetIntegral.h"
+
+#include "package_bgs/lb/LBSimpleGaussian.h"
+#include "package_bgs/lb/LBFuzzyGaussian.h"
+#include "package_bgs/lb/LBMixtureOfGaussians.h"
+#include "package_bgs/lb/LBAdaptiveSOM.h"
+#include "package_bgs/lb/LBFuzzyAdaptiveSOM.h"
+
+#if !defined(_WIN32)
+// Currently this method works only on Linux platform.
+#include "package_bgs/ck/LbpMrf.h"
+#endif
+
+#include "package_bgs/jmo/MultiLayerBGS.h"
+#include "package_bgs/pt/PixelBasedAdaptiveSegmenter.h"
+#include "package_bgs/av/VuMeter.h"
+#include "package_bgs/ae/KDE.h"
+#include "package_bgs/db/IndependentMultimodalBGS.h"
+#include "package_bgs/sjn/SJN_MultiCueBGS.h"
+
+void main(int argc, char **argv)
+{
+  std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl;
+
+  CvCapture *capture = 0;
+  int resize_factor = 100;
+
+  if(argc > 1)
+  {
+    std::cout << "Openning: " << argv[1] << std::endl;
+    capture = cvCaptureFromAVI(argv[1]);
+  }
+  else
+  {
+    capture = cvCaptureFromCAM(0);
+    resize_factor = 50; // set size = 50% of original image
+  }
+
+  if(!capture)
+  {
+    std::cerr << "Cannot initialize video!" << std::endl;
+    return;
+  }
+  
+  IplImage *frame_aux = cvQueryFrame(capture);
+  IplImage *frame = cvCreateImage(cvSize((int)((frame_aux->width*resize_factor)/100) , (int)((frame_aux->height*resize_factor)/100)), frame_aux->depth, frame_aux->nChannels);
+  cvResize(frame_aux, frame);
+
+  /* Background Subtraction Methods */
+  IBGS *bgs;
+
+  /*** Default Package ***/
+  bgs = new FrameDifferenceBGS;
+  //bgs = new StaticFrameDifferenceBGS;
+  //bgs = new WeightedMovingMeanBGS;
+  //bgs = new WeightedMovingVarianceBGS;
+  //bgs = new MixtureOfGaussianV1BGS;
+  //bgs = new MixtureOfGaussianV2BGS;
+  //bgs = new AdaptiveBackgroundLearning;
+  //bgs = new AdaptiveSelectiveBackgroundLearning;
+  //bgs = new GMG;
+  
+  /*** DP Package (thanks to Donovan Parks) ***/
+  //bgs = new DPAdaptiveMedianBGS;
+  //bgs = new DPGrimsonGMMBGS;
+  //bgs = new DPZivkovicAGMMBGS;
+  //bgs = new DPMeanBGS;
+  //bgs = new DPWrenGABGS;
+  //bgs = new DPPratiMediodBGS;
+  //bgs = new DPEigenbackgroundBGS;
+  //bgs = new DPTextureBGS;
+
+  /*** TB Package (thanks to Thierry Bouwmans, Fida EL BAF and Zhenjie Zhao) ***/
+  //bgs = new T2FGMM_UM;
+  //bgs = new T2FGMM_UV;
+  //bgs = new T2FMRF_UM;
+  //bgs = new T2FMRF_UV;
+  //bgs = new FuzzySugenoIntegral;
+  //bgs = new FuzzyChoquetIntegral;
+
+  /*** JMO Package (thanks to Jean-Marc Odobez) ***/
+  //bgs = new MultiLayerBGS;
+
+  /*** PT Package (thanks to Martin Hofmann, Philipp Tiefenbacher and Gerhard Rigoll) ***/
+  //bgs = new PixelBasedAdaptiveSegmenter;
+
+  /*** LB Package (thanks to Laurence Bender) ***/
+  //bgs = new LBSimpleGaussian;
+  //bgs = new LBFuzzyGaussian;
+  //bgs = new LBMixtureOfGaussians;
+  //bgs = new LBAdaptiveSOM;
+  //bgs = new LBFuzzyAdaptiveSOM;
+
+  /*** LBP-MRF Package (thanks to Csaba Kertész) ***/
+  //bgs = new LbpMrf;
+
+  /*** AV Package (thanks to Lionel Robinault and Antoine Vacavant) ***/
+  //bgs = new VuMeter;
+
+  /*** EG Package (thanks to Ahmed Elgammal) ***/
+  //bgs = new KDE;
+  
+  /*** DB Package (thanks to Domenico Daniele Bloisi) ***/
+  //bgs = new IndependentMultimodalBGS;
+
+  /*** SJN Package (thanks to SeungJong Noh) ***/
+  //bgs = new SJN_MultiCueBGS;
+
+  int key = 0;
+  while(key != 'q')
+  {
+    frame_aux = cvQueryFrame(capture);
+    if(!frame_aux) break;
+
+    cvResize(frame_aux, frame);
+    
+    cv::Mat img_input(frame);
+    cv::imshow("input", img_input);
+
+    cv::Mat img_mask;
+    cv::Mat img_bkgmodel;
+    bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image
+    
+    //if(!img_mask.empty())
+    //  cv::imshow("Foreground", img_mask);
+    //  do something
+    
+    key = cvWaitKey(33);
+  }
+
+  delete bgs;
+
+  cvDestroyAllWindows();
+  cvReleaseCapture(&capture);
+}
diff --git a/FrameProcessor.cpp b/FrameProcessor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..585cb9b544d19679b51e7bc5314981118b7da542
--- /dev/null
+++ b/FrameProcessor.cpp
@@ -0,0 +1,557 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "FrameProcessor.h"
+
+FrameProcessor::FrameProcessor() : firstTime(true), frameNumber(0), duration(0), tictoc(""), frameToStop(0)
+{
+  std::cout << "FrameProcessor()" << std::endl;
+
+  loadConfig();
+  saveConfig();
+}
+
+FrameProcessor::~FrameProcessor()
+{
+  std::cout << "~FrameProcessor()" << std::endl;
+}
+
+void FrameProcessor::init()
+{
+  if(enablePreProcessor)
+    preProcessor = new PreProcessor;
+
+  if(enableFrameDifferenceBGS)
+    frameDifference = new FrameDifferenceBGS;
+
+  if(enableStaticFrameDifferenceBGS)
+    staticFrameDifference = new StaticFrameDifferenceBGS;
+
+  if(enableWeightedMovingMeanBGS)
+    weightedMovingMean = new WeightedMovingMeanBGS;
+
+  if(enableWeightedMovingVarianceBGS)
+    weightedMovingVariance = new WeightedMovingVarianceBGS;
+
+  if(enableMixtureOfGaussianV1BGS)
+    mixtureOfGaussianV1BGS = new MixtureOfGaussianV1BGS;
+
+  if(enableMixtureOfGaussianV2BGS)
+    mixtureOfGaussianV2BGS = new MixtureOfGaussianV2BGS;
+
+  if(enableAdaptiveBackgroundLearning)
+    adaptiveBackgroundLearning = new AdaptiveBackgroundLearning;
+
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+  if(enableGMG)
+    gmg = new GMG;
+#endif
+
+  if(enableDPAdaptiveMedianBGS)
+    adaptiveMedian = new DPAdaptiveMedianBGS;
+
+  if(enableDPGrimsonGMMBGS)
+    grimsonGMM = new DPGrimsonGMMBGS;
+
+  if(enableDPZivkovicAGMMBGS)
+    zivkovicAGMM = new DPZivkovicAGMMBGS;
+
+  if(enableDPMeanBGS)
+    temporalMean = new DPMeanBGS;
+
+  if(enableDPWrenGABGS)
+    wrenGA = new DPWrenGABGS;
+
+  if(enableDPPratiMediodBGS)
+    pratiMediod = new DPPratiMediodBGS;
+
+  if(enableDPEigenbackgroundBGS)
+    eigenBackground = new DPEigenbackgroundBGS;
+
+  if(enableDPTextureBGS)
+    textureBGS = new DPTextureBGS;
+
+  if(enableT2FGMM_UM)
+    type2FuzzyGMM_UM = new T2FGMM_UM;
+
+  if(enableT2FGMM_UV)
+    type2FuzzyGMM_UV = new T2FGMM_UV;
+
+  if(enableT2FMRF_UM)
+    type2FuzzyMRF_UM = new T2FMRF_UM;
+
+  if(enableT2FMRF_UV)
+    type2FuzzyMRF_UV = new T2FMRF_UV;
+
+  if(enableFuzzySugenoIntegral)
+    fuzzySugenoIntegral = new FuzzySugenoIntegral;
+
+  if(enableFuzzyChoquetIntegral)
+    fuzzyChoquetIntegral = new FuzzyChoquetIntegral;
+  
+  if(enableLBSimpleGaussian)
+    lbSimpleGaussian = new LBSimpleGaussian;
+
+  if(enableLBFuzzyGaussian)
+    lbFuzzyGaussian = new LBFuzzyGaussian;
+
+  if(enableLBMixtureOfGaussians)
+    lbMixtureOfGaussians = new LBMixtureOfGaussians;
+
+  if(enableLBAdaptiveSOM)
+    lbAdaptiveSOM = new LBAdaptiveSOM;
+
+  if(enableLBFuzzyAdaptiveSOM)
+    lbFuzzyAdaptiveSOM = new LBFuzzyAdaptiveSOM;
+
+  #if !defined(_WIN32)
+  if(enableLbpMrf)
+    lbpMrf = new LbpMrf;
+  #endif
+
+  if(enableMultiLayerBGS)
+    multiLayerBGS = new MultiLayerBGS;
+
+  if(enablePBAS)
+    pixelBasedAdaptiveSegmenter = new PixelBasedAdaptiveSegmenter;
+
+  if(enableVuMeter)
+    vuMeter = new VuMeter;
+
+  if(enableKDE)
+    kde = new KDE;
+
+  if(enableForegroundMaskAnalysis)
+    foregroundMaskAnalysis = new ForegroundMaskAnalysis;
+}
+
+void FrameProcessor::process(std::string name, IBGS *bgs, const cv::Mat &img_input, cv::Mat &img_bgs)
+{
+  if(tictoc == name)
+    tic(name);
+
+  cv::Mat img_bkgmodel;
+  bgs->process(img_input, img_bgs, img_bkgmodel);
+
+  if(tictoc == name)
+    toc();
+}
+
+void FrameProcessor::process(const cv::Mat &img_input)
+{
+  frameNumber++;
+
+  if(enablePreProcessor)
+    preProcessor->process(img_input, img_prep);
+  
+  if(enableFrameDifferenceBGS)
+    process("FrameDifferenceBGS", frameDifference, img_prep, img_framediff);
+  
+  if(enableStaticFrameDifferenceBGS)
+    process("StaticFrameDifferenceBGS", staticFrameDifference, img_prep, img_staticfdiff);
+  
+  if(enableWeightedMovingMeanBGS)
+    process("WeightedMovingMeanBGS", weightedMovingMean, img_prep, img_wmovmean);
+  
+  if(enableWeightedMovingVarianceBGS)
+    process("WeightedMovingVarianceBGS", weightedMovingVariance, img_prep, img_movvar);
+  
+  if(enableMixtureOfGaussianV1BGS)
+    process("MixtureOfGaussianV1BGS", mixtureOfGaussianV1BGS, img_prep, img_mog1);
+  
+  if(enableMixtureOfGaussianV2BGS)
+    process("MixtureOfGaussianV2BGS", mixtureOfGaussianV2BGS, img_prep, img_mog2);
+  
+  if(enableAdaptiveBackgroundLearning)
+    process("AdaptiveBackgroundLearning", adaptiveBackgroundLearning, img_prep, img_bkgl_fgmask);
+
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+  if(enableGMG)
+    process("GMG", gmg, img_prep, img_gmg);
+#endif
+
+  if(enableDPAdaptiveMedianBGS)
+    process("DPAdaptiveMedianBGS", adaptiveMedian, img_prep, img_adpmed);
+  
+  if(enableDPGrimsonGMMBGS)
+    process("DPGrimsonGMMBGS", grimsonGMM, img_prep, img_grigmm);
+  
+  if(enableDPZivkovicAGMMBGS)
+    process("DPZivkovicAGMMBGS", zivkovicAGMM, img_prep, img_zivgmm);
+  
+  if(enableDPMeanBGS)
+    process("DPMeanBGS", temporalMean, img_prep, img_tmpmean);
+  
+  if(enableDPWrenGABGS)
+    process("DPWrenGABGS", wrenGA, img_prep, img_wrenga);
+  
+  if(enableDPPratiMediodBGS)
+    process("DPPratiMediodBGS", pratiMediod, img_prep, img_pramed);
+  
+  if(enableDPEigenbackgroundBGS)
+    process("DPEigenbackgroundBGS", eigenBackground, img_prep, img_eigbkg);
+  
+  if(enableDPTextureBGS)
+    process("DPTextureBGS", textureBGS, img_prep, img_texbgs);
+
+  if(enableT2FGMM_UM)
+    process("T2FGMM_UM", type2FuzzyGMM_UM, img_prep, img_t2fgmm_um);
+
+  if(enableT2FGMM_UV)
+    process("T2FGMM_UV", type2FuzzyGMM_UV, img_prep, img_t2fgmm_uv);
+
+  if(enableT2FMRF_UM)
+    process("T2FMRF_UM", type2FuzzyMRF_UM, img_prep, img_t2fmrf_um);
+
+  if(enableT2FMRF_UV)
+    process("T2FMRF_UV", type2FuzzyMRF_UV, img_prep, img_t2fmrf_uv);
+
+  if(enableFuzzySugenoIntegral)
+    process("FuzzySugenoIntegral", fuzzySugenoIntegral, img_prep, img_fsi);
+
+  if(enableFuzzyChoquetIntegral)
+    process("FuzzyChoquetIntegral", fuzzyChoquetIntegral, img_prep, img_fci);
+
+  if(enableLBSimpleGaussian)
+    process("LBSimpleGaussian", lbSimpleGaussian, img_prep, img_lb_sg);
+  
+  if(enableLBFuzzyGaussian)
+    process("LBFuzzyGaussian", lbFuzzyGaussian, img_prep, img_lb_fg);
+
+  if(enableLBMixtureOfGaussians)
+    process("LBMixtureOfGaussians", lbMixtureOfGaussians, img_prep, img_lb_mog);
+
+  if(enableLBAdaptiveSOM)
+    process("LBAdaptiveSOM", lbAdaptiveSOM, img_prep, img_lb_som);
+
+  if(enableLBFuzzyAdaptiveSOM)
+    process("LBFuzzyAdaptiveSOM", lbFuzzyAdaptiveSOM, img_prep, img_lb_fsom);
+
+  #if !defined(_WIN32)
+  if(enableLbpMrf)
+    process("LbpMrf", lbpMrf, img_prep, img_lbp_mrf);
+  #endif
+
+  if(enableMultiLayerBGS)
+  {
+    multiLayerBGS->setStatus(MultiLayerBGS::Status::MLBGS_LEARN);
+    //multiLayerBGS->setStatus(MultiLayerBGS::Status::MLBGS_DETECT);
+    process("MultiLayerBGS", multiLayerBGS, img_prep, img_mlbgs);
+  }
+  
+  if(enablePBAS)
+    process("PBAS", pixelBasedAdaptiveSegmenter, img_prep, img_pt_pbas);
+  
+  if(enableVuMeter)
+    process("VuMeter", vuMeter, img_prep, img_vumeter);
+  
+  if(enableKDE)
+    process("KDE", kde, img_prep, img_kde);
+
+  if(enableForegroundMaskAnalysis)
+  {
+    foregroundMaskAnalysis->stopAt = frameToStop;
+    foregroundMaskAnalysis->img_ref_path = imgref;
+
+    foregroundMaskAnalysis->process(frameNumber, "FrameDifferenceBGS", img_framediff);
+    foregroundMaskAnalysis->process(frameNumber, "StaticFrameDifferenceBGS", img_staticfdiff);
+    foregroundMaskAnalysis->process(frameNumber, "WeightedMovingMeanBGS", img_wmovmean);
+    foregroundMaskAnalysis->process(frameNumber, "WeightedMovingVarianceBGS", img_movvar);
+    foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV1BGS", img_mog1);
+    foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV2BGS", img_mog2);
+    foregroundMaskAnalysis->process(frameNumber, "AdaptiveBackgroundLearning", img_bkgl_fgmask);
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+    foregroundMaskAnalysis->process(frameNumber, "GMG", img_gmg);
+#endif
+    foregroundMaskAnalysis->process(frameNumber, "DPAdaptiveMedianBGS", img_adpmed);
+    foregroundMaskAnalysis->process(frameNumber, "DPGrimsonGMMBGS", img_grigmm);
+    foregroundMaskAnalysis->process(frameNumber, "DPZivkovicAGMMBGS", img_zivgmm);
+    foregroundMaskAnalysis->process(frameNumber, "DPMeanBGS", img_tmpmean);
+    foregroundMaskAnalysis->process(frameNumber, "DPWrenGABGS", img_wrenga);
+    foregroundMaskAnalysis->process(frameNumber, "DPPratiMediodBGS", img_pramed);
+    foregroundMaskAnalysis->process(frameNumber, "DPEigenbackgroundBGS", img_eigbkg);
+    foregroundMaskAnalysis->process(frameNumber, "DPTextureBGS", img_texbgs);
+    foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UM", img_t2fgmm_um);
+    foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UV", img_t2fgmm_uv);
+    foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UM", img_t2fmrf_um);
+    foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UV", img_t2fmrf_uv);
+    foregroundMaskAnalysis->process(frameNumber, "FuzzySugenoIntegral", img_fsi);
+    foregroundMaskAnalysis->process(frameNumber, "FuzzyChoquetIntegral", img_fci);
+    foregroundMaskAnalysis->process(frameNumber, "LBSimpleGaussian", img_lb_sg);
+    foregroundMaskAnalysis->process(frameNumber, "LBFuzzyGaussian", img_lb_fg);
+    foregroundMaskAnalysis->process(frameNumber, "LBMixtureOfGaussians", img_lb_mog);
+    foregroundMaskAnalysis->process(frameNumber, "LBAdaptiveSOM", img_lb_som);
+    foregroundMaskAnalysis->process(frameNumber, "LBFuzzyAdaptiveSOM", img_lb_fsom);
+	#if !defined(_WIN32)
+    foregroundMaskAnalysis->process(frameNumber, "LbpMrf", img_lbp_mrf);
+	#endif
+    foregroundMaskAnalysis->process(frameNumber, "MultiLayerBGS", img_mlbgs);
+    foregroundMaskAnalysis->process(frameNumber, "PBAS", img_pt_pbas);
+    foregroundMaskAnalysis->process(frameNumber, "VuMeter", img_vumeter);
+    foregroundMaskAnalysis->process(frameNumber, "KDE", img_kde);
+  }
+
+  firstTime = false;
+}
+
+void FrameProcessor::finish(void)
+{
+  /*if(enableMultiLayerBGS)
+    multiLayerBGS->finish();
+
+  if(enableLBSimpleGaussian)
+    lbSimpleGaussian->finish();
+  
+  if(enableLBFuzzyGaussian)
+    lbFuzzyGaussian->finish();
+
+  if(enableLBMixtureOfGaussians)
+    lbMixtureOfGaussians->finish();
+
+  if(enableLBAdaptiveSOM)
+    lbAdaptiveSOM->finish();
+
+  if(enableLBFuzzyAdaptiveSOM)
+    lbFuzzyAdaptiveSOM->finish();*/
+  
+  if(enableForegroundMaskAnalysis)
+    delete foregroundMaskAnalysis;
+  
+  if(enableKDE)
+    delete kde;
+  
+  if(enableVuMeter)
+    delete vuMeter;
+  
+  if(enablePBAS)
+    delete pixelBasedAdaptiveSegmenter;
+
+  if(enableMultiLayerBGS)
+    delete multiLayerBGS;
+  
+  if(enableLBFuzzyAdaptiveSOM)
+    delete lbFuzzyAdaptiveSOM;
+
+  if(enableLBAdaptiveSOM)
+    delete lbAdaptiveSOM;
+
+  if(enableLBMixtureOfGaussians)
+    delete lbMixtureOfGaussians;
+
+  if(enableLBFuzzyGaussian)
+    delete lbFuzzyGaussian;
+
+  if(enableLBSimpleGaussian)
+    delete lbSimpleGaussian;
+
+  #if !defined(_WIN32)
+  if(enableLbpMrf)
+    delete lbpMrf;
+  #endif
+
+  if(enableFuzzyChoquetIntegral)
+    delete fuzzyChoquetIntegral;
+
+  if(enableFuzzySugenoIntegral)
+    delete fuzzySugenoIntegral;
+
+  if(enableT2FMRF_UV)
+    delete type2FuzzyMRF_UV;
+
+  if(enableT2FMRF_UM)
+    delete type2FuzzyMRF_UM;
+
+  if(enableT2FGMM_UV)
+    delete type2FuzzyGMM_UV;
+
+  if(enableT2FGMM_UM)
+    delete type2FuzzyGMM_UM;
+
+  if(enableDPTextureBGS)
+    delete textureBGS;
+
+  if(enableDPEigenbackgroundBGS)
+    delete eigenBackground;
+
+  if(enableDPPratiMediodBGS)
+    delete pratiMediod;
+
+  if(enableDPWrenGABGS)
+    delete wrenGA;
+
+  if(enableDPMeanBGS)
+    delete temporalMean;
+
+  if(enableDPZivkovicAGMMBGS)
+    delete zivkovicAGMM;
+
+  if(enableDPGrimsonGMMBGS)
+    delete grimsonGMM;
+
+  if(enableDPAdaptiveMedianBGS)
+    delete adaptiveMedian;
+
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+  if(enableGMG)
+    delete gmg;
+#endif
+
+  if(enableAdaptiveBackgroundLearning)
+    delete adaptiveBackgroundLearning;
+
+  if(enableMixtureOfGaussianV2BGS)
+    delete mixtureOfGaussianV2BGS;
+
+  if(enableMixtureOfGaussianV1BGS)
+    delete mixtureOfGaussianV1BGS;
+
+  if(enableWeightedMovingVarianceBGS)
+    delete weightedMovingVariance;
+
+  if(enableWeightedMovingMeanBGS)
+    delete weightedMovingMean;
+
+  if(enableStaticFrameDifferenceBGS)
+    delete staticFrameDifference;
+
+  if(enableFrameDifferenceBGS)
+    delete frameDifference;
+
+  if(enablePreProcessor)
+    delete preProcessor;
+}
+
+void FrameProcessor::tic(std::string value)
+{
+  processname = value;
+  duration = static_cast<double>(cv::getTickCount());
+}
+
+void FrameProcessor::toc()
+{
+  duration = (static_cast<double>(cv::getTickCount()) - duration)/cv::getTickFrequency();
+  std::cout << processname << "\ttime(sec):" << std::fixed << std::setprecision(6) << duration << std::endl;
+}
+
+void FrameProcessor::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FrameProcessor.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteString(fs, "tictoc", tictoc.c_str());
+
+  cvWriteInt(fs, "enablePreProcessor", enablePreProcessor);
+  
+  cvWriteInt(fs, "enableForegroundMaskAnalysis", enableForegroundMaskAnalysis);
+
+  cvWriteInt(fs, "enableFrameDifferenceBGS", enableFrameDifferenceBGS);
+  cvWriteInt(fs, "enableStaticFrameDifferenceBGS", enableStaticFrameDifferenceBGS);
+  cvWriteInt(fs, "enableWeightedMovingMeanBGS", enableWeightedMovingMeanBGS);
+  cvWriteInt(fs, "enableWeightedMovingVarianceBGS", enableWeightedMovingVarianceBGS);
+  cvWriteInt(fs, "enableMixtureOfGaussianV1BGS", enableMixtureOfGaussianV1BGS);
+  cvWriteInt(fs, "enableMixtureOfGaussianV2BGS", enableMixtureOfGaussianV2BGS);
+  cvWriteInt(fs, "enableAdaptiveBackgroundLearning", enableAdaptiveBackgroundLearning);
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+  cvWriteInt(fs, "enableGMG", enableGMG);
+#endif
+  
+  cvWriteInt(fs, "enableDPAdaptiveMedianBGS", enableDPAdaptiveMedianBGS);
+  cvWriteInt(fs, "enableDPGrimsonGMMBGS", enableDPGrimsonGMMBGS);
+  cvWriteInt(fs, "enableDPZivkovicAGMMBGS", enableDPZivkovicAGMMBGS);
+  cvWriteInt(fs, "enableDPMeanBGS", enableDPMeanBGS);
+  cvWriteInt(fs, "enableDPWrenGABGS", enableDPWrenGABGS);
+  cvWriteInt(fs, "enableDPPratiMediodBGS", enableDPPratiMediodBGS);
+  cvWriteInt(fs, "enableDPEigenbackgroundBGS", enableDPEigenbackgroundBGS);
+  cvWriteInt(fs, "enableDPTextureBGS", enableDPTextureBGS);
+
+  cvWriteInt(fs, "enableT2FGMM_UM", enableT2FGMM_UM);
+  cvWriteInt(fs, "enableT2FGMM_UV", enableT2FGMM_UV);
+  cvWriteInt(fs, "enableT2FMRF_UM", enableT2FMRF_UM);
+  cvWriteInt(fs, "enableT2FMRF_UV", enableT2FMRF_UV);
+  cvWriteInt(fs, "enableFuzzySugenoIntegral", enableFuzzySugenoIntegral);
+  cvWriteInt(fs, "enableFuzzyChoquetIntegral", enableFuzzyChoquetIntegral);
+
+  cvWriteInt(fs, "enableLBSimpleGaussian", enableLBSimpleGaussian);
+  cvWriteInt(fs, "enableLBFuzzyGaussian", enableLBFuzzyGaussian);
+  cvWriteInt(fs, "enableLBMixtureOfGaussians", enableLBMixtureOfGaussians);
+  cvWriteInt(fs, "enableLBAdaptiveSOM", enableLBAdaptiveSOM);
+  cvWriteInt(fs, "enableLBFuzzyAdaptiveSOM", enableLBFuzzyAdaptiveSOM);
+
+  #if !defined(_WIN32)
+  cvWriteInt(fs, "enableLbpMrf", enableLbpMrf);
+  #endif
+
+  cvWriteInt(fs, "enableMultiLayerBGS", enableMultiLayerBGS);
+  cvWriteInt(fs, "enablePBAS", enablePBAS);
+  cvWriteInt(fs, "enableVuMeter", enableVuMeter);
+  cvWriteInt(fs, "enableKDE", enableKDE);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void FrameProcessor::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FrameProcessor.xml", 0, CV_STORAGE_READ);
+  
+  tictoc = cvReadStringByName(fs, 0, "tictoc", "");
+
+  enablePreProcessor = cvReadIntByName(fs, 0, "enablePreProcessor", true);
+
+  enableForegroundMaskAnalysis = cvReadIntByName(fs, 0, "enableForegroundMaskAnalysis", false);
+  
+  enableFrameDifferenceBGS = cvReadIntByName(fs, 0, "enableFrameDifferenceBGS", false);
+  enableStaticFrameDifferenceBGS = cvReadIntByName(fs, 0, "enableStaticFrameDifferenceBGS", false);
+  enableWeightedMovingMeanBGS = cvReadIntByName(fs, 0, "enableWeightedMovingMeanBGS", false);
+  enableWeightedMovingVarianceBGS = cvReadIntByName(fs, 0, "enableWeightedMovingVarianceBGS", false);
+  enableMixtureOfGaussianV1BGS = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV1BGS", false);
+  enableMixtureOfGaussianV2BGS = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV2BGS", false);
+  enableAdaptiveBackgroundLearning = cvReadIntByName(fs, 0, "enableAdaptiveBackgroundLearning", false);
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+  enableGMG = cvReadIntByName(fs, 0, "enableGMG", false);
+#endif
+
+  enableDPAdaptiveMedianBGS = cvReadIntByName(fs, 0, "enableDPAdaptiveMedianBGS", false);
+  enableDPGrimsonGMMBGS = cvReadIntByName(fs, 0, "enableDPGrimsonGMMBGS", false);
+  enableDPZivkovicAGMMBGS = cvReadIntByName(fs, 0, "enableDPZivkovicAGMMBGS", false);
+  enableDPMeanBGS = cvReadIntByName(fs, 0, "enableDPMeanBGS", false);
+  enableDPWrenGABGS = cvReadIntByName(fs, 0, "enableDPWrenGABGS", false);
+  enableDPPratiMediodBGS = cvReadIntByName(fs, 0, "enableDPPratiMediodBGS", false);
+  enableDPEigenbackgroundBGS = cvReadIntByName(fs, 0, "enableDPEigenbackgroundBGS", false);
+  enableDPTextureBGS = cvReadIntByName(fs, 0, "enableDPTextureBGS", false);
+
+  enableT2FGMM_UM = cvReadIntByName(fs, 0, "enableT2FGMM_UM", false);
+  enableT2FGMM_UV = cvReadIntByName(fs, 0, "enableT2FGMM_UV", false);
+  enableT2FMRF_UM = cvReadIntByName(fs, 0, "enableT2FMRF_UM", false);
+  enableT2FMRF_UV = cvReadIntByName(fs, 0, "enableT2FMRF_UV", false);
+  enableFuzzySugenoIntegral = cvReadIntByName(fs, 0, "enableFuzzySugenoIntegral", false);
+  enableFuzzyChoquetIntegral = cvReadIntByName(fs, 0, "enableFuzzyChoquetIntegral", false);
+
+  enableLBSimpleGaussian = cvReadIntByName(fs, 0, "enableLBSimpleGaussian", false);
+  enableLBFuzzyGaussian = cvReadIntByName(fs, 0, "enableLBFuzzyGaussian", false);
+  enableLBMixtureOfGaussians = cvReadIntByName(fs, 0, "enableLBMixtureOfGaussians", false);
+  enableLBAdaptiveSOM = cvReadIntByName(fs, 0, "enableLBAdaptiveSOM", false);
+  enableLBFuzzyAdaptiveSOM = cvReadIntByName(fs, 0, "enableLBFuzzyAdaptiveSOM", false);
+
+  #if !defined(_WIN32)
+  enableLbpMrf = cvReadIntByName(fs, 0, "enableLbpMrf", false);
+  #endif
+
+  enableMultiLayerBGS = cvReadIntByName(fs, 0, "enableMultiLayerBGS", false);
+  enablePBAS = cvReadIntByName(fs, 0, "enablePBAS", false);
+  enableVuMeter = cvReadIntByName(fs, 0, "enableVuMeter", false);
+  enableKDE = cvReadIntByName(fs, 0, "enableKDE", false);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/FrameProcessor.h b/FrameProcessor.h
new file mode 100644
index 0000000000000000000000000000000000000000..44ad2aa6c7939a58371516a03c01d7386e58757c
--- /dev/null
+++ b/FrameProcessor.h
@@ -0,0 +1,235 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+#pragma warning(disable : 4482)
+
+#include "IFrameProcessor.h"
+#include "PreProcessor.h"
+
+#include "package_bgs/IBGS.h"
+
+#include "package_bgs/FrameDifferenceBGS.h"
+#include "package_bgs/StaticFrameDifferenceBGS.h"
+#include "package_bgs/WeightedMovingMeanBGS.h"
+#include "package_bgs/WeightedMovingVarianceBGS.h"
+#include "package_bgs/MixtureOfGaussianV1BGS.h"
+#include "package_bgs/MixtureOfGaussianV2BGS.h"
+#include "package_bgs/AdaptiveBackgroundLearning.h"
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+#include "package_bgs/GMG.h"
+#endif
+
+#include "package_bgs/dp/DPAdaptiveMedianBGS.h"
+#include "package_bgs/dp/DPGrimsonGMMBGS.h"
+#include "package_bgs/dp/DPZivkovicAGMMBGS.h"
+#include "package_bgs/dp/DPMeanBGS.h"
+#include "package_bgs/dp/DPWrenGABGS.h"
+#include "package_bgs/dp/DPPratiMediodBGS.h"
+#include "package_bgs/dp/DPEigenbackgroundBGS.h"
+#include "package_bgs/dp/DPTextureBGS.h"
+
+#include "package_bgs/tb/T2FGMM_UM.h"
+#include "package_bgs/tb/T2FGMM_UV.h"
+#include "package_bgs/tb/T2FMRF_UM.h"
+#include "package_bgs/tb/T2FMRF_UV.h"
+#include "package_bgs/tb/FuzzySugenoIntegral.h"
+#include "package_bgs/tb/FuzzyChoquetIntegral.h"
+
+#include "package_bgs/lb/LBSimpleGaussian.h"
+#include "package_bgs/lb/LBFuzzyGaussian.h"
+#include "package_bgs/lb/LBMixtureOfGaussians.h"
+#include "package_bgs/lb/LBAdaptiveSOM.h"
+#include "package_bgs/lb/LBFuzzyAdaptiveSOM.h"
+
+#if !defined(_WIN32)
+#include "package_bgs/ck/LbpMrf.h"
+#endif
+
+#include "package_bgs/jmo/MultiLayerBGS.h"
+#include "package_bgs/pt/PixelBasedAdaptiveSegmenter.h"
+#include "package_bgs/av/VuMeter.h"
+#include "package_bgs/ae/KDE.h"
+
+#include "package_analysis/ForegroundMaskAnalysis.h"
+
+class FrameProcessor : public IFrameProcessor
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  std::string processname;
+  double duration;
+  std::string tictoc;
+
+  cv::Mat img_prep;
+  PreProcessor* preProcessor;
+  bool enablePreProcessor;
+  
+  cv::Mat img_framediff;
+  FrameDifferenceBGS* frameDifference;
+  bool enableFrameDifferenceBGS;
+  
+  cv::Mat img_staticfdiff;
+  StaticFrameDifferenceBGS* staticFrameDifference;
+  bool enableStaticFrameDifferenceBGS;
+
+  cv::Mat img_wmovmean;
+  WeightedMovingMeanBGS* weightedMovingMean;
+  bool enableWeightedMovingMeanBGS;
+
+  cv::Mat img_movvar;
+  WeightedMovingVarianceBGS* weightedMovingVariance;
+  bool enableWeightedMovingVarianceBGS;
+
+  cv::Mat img_mog1;
+  MixtureOfGaussianV1BGS* mixtureOfGaussianV1BGS;
+  bool enableMixtureOfGaussianV1BGS;
+
+  cv::Mat img_mog2;
+  MixtureOfGaussianV2BGS* mixtureOfGaussianV2BGS;
+  bool enableMixtureOfGaussianV2BGS;
+
+  cv::Mat img_bkgl_fgmask;
+  AdaptiveBackgroundLearning* adaptiveBackgroundLearning;
+  bool enableAdaptiveBackgroundLearning;
+
+#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3
+  cv::Mat img_gmg;
+  GMG* gmg;
+  bool enableGMG;
+#endif
+
+  cv::Mat img_adpmed;
+  DPAdaptiveMedianBGS* adaptiveMedian;
+  bool enableDPAdaptiveMedianBGS;
+
+  cv::Mat img_grigmm;
+  DPGrimsonGMMBGS* grimsonGMM;
+  bool enableDPGrimsonGMMBGS;
+
+  cv::Mat img_zivgmm;
+  DPZivkovicAGMMBGS* zivkovicAGMM;
+  bool enableDPZivkovicAGMMBGS;
+
+  cv::Mat img_tmpmean;
+  DPMeanBGS* temporalMean;
+  bool enableDPMeanBGS;
+
+  cv::Mat img_wrenga;
+  DPWrenGABGS* wrenGA;
+  bool enableDPWrenGABGS;
+
+  cv::Mat img_pramed;
+  DPPratiMediodBGS* pratiMediod;
+  bool enableDPPratiMediodBGS;
+
+  cv::Mat img_eigbkg;
+  DPEigenbackgroundBGS* eigenBackground;
+  bool enableDPEigenbackgroundBGS;
+
+  cv::Mat img_texbgs;
+  DPTextureBGS* textureBGS;
+  bool enableDPTextureBGS;
+
+  cv::Mat img_t2fgmm_um;
+  T2FGMM_UM* type2FuzzyGMM_UM;
+  bool enableT2FGMM_UM;
+
+  cv::Mat img_t2fgmm_uv;
+  T2FGMM_UV* type2FuzzyGMM_UV;
+  bool enableT2FGMM_UV;
+
+  cv::Mat img_t2fmrf_um;
+  T2FMRF_UM* type2FuzzyMRF_UM;
+  bool enableT2FMRF_UM;
+
+  cv::Mat img_t2fmrf_uv;
+  T2FMRF_UV* type2FuzzyMRF_UV;
+  bool enableT2FMRF_UV;
+
+  cv::Mat img_fsi;
+  FuzzySugenoIntegral* fuzzySugenoIntegral;
+  bool enableFuzzySugenoIntegral;
+
+  cv::Mat img_fci;
+  FuzzyChoquetIntegral* fuzzyChoquetIntegral;
+  bool enableFuzzyChoquetIntegral;
+  
+  cv::Mat img_lb_sg;
+  LBSimpleGaussian* lbSimpleGaussian;
+  bool enableLBSimpleGaussian;
+
+  cv::Mat img_lb_fg;
+  LBFuzzyGaussian* lbFuzzyGaussian;
+  bool enableLBFuzzyGaussian;
+
+  cv::Mat img_lb_mog;
+  LBMixtureOfGaussians* lbMixtureOfGaussians;
+  bool enableLBMixtureOfGaussians;
+
+  cv::Mat img_lb_som;
+  LBAdaptiveSOM* lbAdaptiveSOM;
+  bool enableLBAdaptiveSOM;
+
+  cv::Mat img_lb_fsom;
+  LBFuzzyAdaptiveSOM* lbFuzzyAdaptiveSOM;
+  bool enableLBFuzzyAdaptiveSOM;
+
+  #if !defined(_WIN32)
+  cv::Mat img_lbp_mrf;
+  LbpMrf* lbpMrf;
+  bool enableLbpMrf;
+  #endif
+  
+  cv::Mat img_mlbgs;
+  MultiLayerBGS* multiLayerBGS;
+  bool enableMultiLayerBGS;
+
+  cv::Mat img_pt_pbas;
+  PixelBasedAdaptiveSegmenter* pixelBasedAdaptiveSegmenter;
+  bool enablePBAS;
+
+  cv::Mat img_vumeter;
+  VuMeter* vuMeter;
+  bool enableVuMeter;
+
+  cv::Mat img_kde;
+  KDE* kde;
+  bool enableKDE;
+
+  ForegroundMaskAnalysis* foregroundMaskAnalysis;
+  bool enableForegroundMaskAnalysis;
+
+public:
+  FrameProcessor();
+  ~FrameProcessor();
+
+  long frameToStop;
+  std::string imgref;
+
+  void init();
+  void process(const cv::Mat &img_input);
+  void finish(void);
+
+private:
+  void process(std::string name, IBGS *bgs, const cv::Mat &img_input, cv::Mat &img_bgs);
+  void tic(std::string value);
+  void toc();
+
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/IFrameProcessor.h b/IFrameProcessor.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef50b1ff9d5b44effdc3d2f44c138417ac83205f
--- /dev/null
+++ b/IFrameProcessor.h
@@ -0,0 +1,26 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <cv.h>
+
+class IFrameProcessor
+{
+  public:
+  virtual void process(const cv:: Mat &input) = 0;
+  virtual ~IFrameProcessor(){}
+};
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e2ce0d8b1060343138fcd323c66fc027c4308051
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,12 @@
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
\ No newline at end of file
diff --git a/Main.cpp b/Main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4e59ee5b2d9d644b8f6989fbf030d9b0f0748e15
--- /dev/null
+++ b/Main.cpp
@@ -0,0 +1,82 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "Config.h"
+#include "VideoAnalysis.h"
+#include <iostream>
+
+class Main
+{
+private:
+  Main();
+
+public:
+  static void start(int argc, const char **argv)
+  {
+    std::cout << "-----------------------------------------" << std::endl;
+    std::cout << "Background Subtraction Library v1.7.0     " << std::endl;
+    std::cout << "http://code.google.com/p/bgslibrary       " << std::endl;
+    std::cout << "by:                                       " << std::endl;
+    std::cout << "Andrews Sobral (andrewssobral@gmail.com)  " << std::endl;
+    std::cout << "-----------------------------------------" << std::endl;
+    std::cout << "Using OpenCV version " << CV_VERSION << std::endl;
+    
+    try
+    {
+      int key = KEY_ESC;
+
+      do
+      {
+        VideoAnalysis* videoAnalysis = new VideoAnalysis;
+
+        if(videoAnalysis->setup(argc, argv))
+        {
+          videoAnalysis->start();
+
+          std::cout << "Processing finished, enter:" << std::endl;
+          std::cout << "R - Repeat" << std::endl;
+          std::cout << "Q - Quit" << std::endl;
+
+          key = cv::waitKey();
+        }
+
+        cv::destroyAllWindows();
+        delete videoAnalysis;
+
+      }while(key == KEY_REPEAT);
+    }
+    catch(const std::exception& ex)
+    {
+      std::cout << "std::exception:" << ex.what() << std::endl;
+      return;
+    }
+    catch(...)
+    {
+      std::cout << "Unknow error" << std::endl;
+      return;
+    }
+
+#ifdef WIN32
+    //system("pause");
+#endif
+  }
+};
+
+int main(int argc, const char **argv)
+{
+  Main::start(argc, argv);
+  return 0;
+}
diff --git a/PreProcessor.cpp b/PreProcessor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..834996bb82d44e9498edf4a4ec7b7c54afdcedd3
--- /dev/null
+++ b/PreProcessor.cpp
@@ -0,0 +1,146 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "PreProcessor.h"
+
+PreProcessor::PreProcessor() : firstTime(true), equalizeHist(false), gaussianBlur(false)
+{
+  std::cout << "PreProcessor()" << std::endl;
+}
+
+PreProcessor::~PreProcessor()
+{
+  std::cout << "~PreProcessor()" << std::endl;
+}
+
+void PreProcessor::setEqualizeHist(bool value)
+{
+  equalizeHist = value;
+}
+
+void PreProcessor::setGaussianBlur(bool value)
+{
+  gaussianBlur = value;
+}
+
+cv::Mat PreProcessor::getGrayScale()
+{
+  return img_gray.clone();
+}
+
+void PreProcessor::process(const cv::Mat &img_input, cv::Mat &img_output)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+  
+  img_input.copyTo(img_output);
+  
+  // Converts image from one color space to another
+  // http://opencv.willowgarage.com/documentation/cpp/miscellaneous_image_transformations.html#cv-cvtcolor
+  cv::cvtColor(img_input, img_gray, CV_BGR2GRAY);
+  //img_gray.copyTo(img_output);
+
+  // Equalizes the histogram of a grayscale image
+  // http://opencv.willowgarage.com/documentation/cpp/histograms.html#cv-equalizehist
+  if(equalizeHist)
+    cv::equalizeHist(img_output, img_output);
+
+  // Smoothes image using a Gaussian filter
+  // http://opencv.willowgarage.com/documentation/cpp/imgproc_image_filtering.html#GaussianBlur
+  if(gaussianBlur)
+    cv::GaussianBlur(img_output, img_output, cv::Size(7,7), 1.5);
+
+  if(enableShow)
+    cv::imshow("Pre Processor", img_output);
+
+  firstTime = false;
+}
+
+void PreProcessor::rotate(const cv::Mat &img_input, cv::Mat &img_output, float angle)
+{
+  IplImage* image = new IplImage(img_input); 
+
+  //IplImage *rotatedImage = cvCreateImage(cvSize(480,320), IPL_DEPTH_8U, image->nChannels);
+  //IplImage *rotatedImage = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, image->nChannels);
+  IplImage* rotatedImage = cvCreateImage(cvSize(image->height,image->width), IPL_DEPTH_8U, image->nChannels);
+
+  CvPoint2D32f center;
+  //center.x = 160;
+  //center.y = 160;
+  center.x = (image->height / 2);
+  center.y = (image->width / 2);
+  
+  CvMat* mapMatrix = cvCreateMat(2, 3, CV_32FC1);
+
+  cv2DRotationMatrix(center, angle, 1.0, mapMatrix);
+  cvWarpAffine(image, rotatedImage, mapMatrix, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0));
+
+  cv::Mat img_rot(rotatedImage);
+  img_rot.copyTo(img_output);
+
+  cvReleaseImage(&image);
+  cvReleaseImage(&rotatedImage);
+  cvReleaseMat(&mapMatrix);
+}
+
+void PreProcessor::applyCanny(const cv::Mat &img_input, cv::Mat &img_output)
+{
+  if(img_input.empty())
+    return;
+
+  //------------------------------------------------------------------
+  // Canny
+  // Finds edges in an image using Canny algorithm.
+  // http://opencv.willowgarage.com/documentation/cpp/imgproc_feature_detection.html#cv-canny
+  //------------------------------------------------------------------
+
+  cv::Mat img_canny;
+  cv::Canny(
+    img_input, // image � Single-channel 8-bit input image
+    img_canny,  // edges � The output edge map. It will have the same size and the same type as image
+    100,       // threshold1 � The first threshold for the hysteresis procedure
+    200);      // threshold2 � The second threshold for the hysteresis procedure
+  cv::threshold(img_canny, img_canny, 128, 255, cv::THRESH_BINARY_INV);
+
+  img_canny.copyTo(img_output);
+}
+
+void PreProcessor::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/PreProcessor.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "equalizeHist", equalizeHist);
+  cvWriteInt(fs, "gaussianBlur", gaussianBlur);
+  cvWriteInt(fs, "enableShow", enableShow);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void PreProcessor::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/PreProcessor.xml", 0, CV_STORAGE_READ);
+
+  equalizeHist = cvReadIntByName(fs, 0, "equalizeHist", false);
+  gaussianBlur = cvReadIntByName(fs, 0, "gaussianBlur", false);
+  enableShow = cvReadIntByName(fs, 0, "enableShow", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/PreProcessor.h b/PreProcessor.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a0462366ec4821a1a803050619ccd3f0189b2ed
--- /dev/null
+++ b/PreProcessor.h
@@ -0,0 +1,49 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+class PreProcessor
+{
+private:
+  bool firstTime;
+  bool equalizeHist;
+  bool gaussianBlur;
+  cv::Mat img_gray;
+  bool enableShow;
+
+public:
+  PreProcessor();
+  ~PreProcessor();
+
+  void setEqualizeHist(bool value);
+  void setGaussianBlur(bool value);
+  cv::Mat getGrayScale(); 
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output);
+
+  void rotate(const cv::Mat &img_input, cv::Mat &img_output, float angle);
+  void applyCanny(const cv::Mat &img_input, cv::Mat &img_output);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b7fe6c5137dfa447f8700abf859b976211c71bfb
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,16 @@
+#
+# HOW TO COMPILE ON LINUX
+#
+# Requirements:
+# cmake >= 2.8
+# opencv >= 2.3.1
+
+cd build
+cmake ..
+make
+cd ..
+
+chmod +x run_video.sh run_camera.sh run_demo.sh
+./run_video.sh
+./run_camera.sh
+./run_demo.sh
diff --git a/VideoAnalysis.cpp b/VideoAnalysis.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0123933b9f29b21ce42f6142a7ebda87ff7f9de3
--- /dev/null
+++ b/VideoAnalysis.cpp
@@ -0,0 +1,130 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "VideoAnalysis.h"
+
+VideoAnalysis::VideoAnalysis() : use_file(false), use_camera(false), cameraIndex(0), use_comp(false), frameToStop(0)
+{
+  std::cout << "VideoAnalysis()" << std::endl;
+}
+
+VideoAnalysis::~VideoAnalysis()
+{
+  std::cout << "~VideoAnalysis()" << std::endl;
+}
+
+bool VideoAnalysis::setup(int argc, const char **argv)
+{
+  bool flag = false;
+  
+  const char* keys =
+  "{hp|help|false|Print help message}"
+  "{uf|use_file|false|Use video file}"
+  "{fn|filename||Specify video file}"
+  "{uc|use_cam|false|Use camera}"
+  "{ca|camera|0|Specify camera index}"
+  "{co|use_comp|false|Use mask comparator}"
+  "{st|stopAt|0|Frame number to stop}"
+  "{im|imgref||Specify image file}"
+  ;
+  cv::CommandLineParser cmd(argc, argv, keys);
+  
+  if(argc <= 1 || cmd.get<bool>("help") == true)
+  {
+    std::cout << "Usage: " << argv[0] << " [options]" << std::endl;
+    std::cout << "Avaible options:" << std::endl;
+    cmd.printParams();
+    return false;
+  }
+
+  use_file = cmd.get<bool>("use_file");
+  if(use_file)
+  {
+    filename = cmd.get<std::string>("filename");
+
+    if(filename.empty())
+    {
+      std::cout << "Specify filename"<< std::endl;
+      return false;
+    }
+    
+    flag = true;
+  }
+
+  use_camera = cmd.get<bool>("use_cam");
+  if(use_camera)
+  {
+    cameraIndex = cmd.get<int>("camera");
+    flag = true;
+  }
+
+  if(flag == true)
+  {
+    use_comp = cmd.get<bool>("use_comp");
+    if(use_comp)
+    {
+      frameToStop = cmd.get<int>("stopAt");
+      imgref = cmd.get<std::string>("imgref");
+
+      if(imgref.empty())
+      {
+        std::cout << "Specify image reference"<< std::endl;
+        return false;
+      }
+    }
+  }
+
+  return flag;
+}
+
+void VideoAnalysis::start()
+{
+  do
+  {
+    videoCapture = new VideoCapture;
+    frameProcessor = new FrameProcessor;
+
+    frameProcessor->init();
+    frameProcessor->frameToStop = frameToStop;
+    frameProcessor->imgref = imgref;
+
+    videoCapture->setFrameProcessor(frameProcessor);
+
+    if(use_file)
+      videoCapture->setVideo(filename);
+    
+    if(use_camera)
+      videoCapture->setCamera(cameraIndex);
+    
+    videoCapture->start();
+
+    if(use_file || use_camera)
+      break;
+
+    frameProcessor->finish();
+
+    int key = cvWaitKey(500);
+    if(key == KEY_ESC)
+      break;
+
+    delete frameProcessor;
+    delete videoCapture;
+
+  }while(1);
+  
+  delete frameProcessor;
+  delete videoCapture;
+}
\ No newline at end of file
diff --git a/VideoAnalysis.h b/VideoAnalysis.h
new file mode 100644
index 0000000000000000000000000000000000000000..74eacf764cc8a49655c23b897ca7b73f76eef4e9
--- /dev/null
+++ b/VideoAnalysis.h
@@ -0,0 +1,45 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <sstream>
+
+#include "VideoCapture.h"
+#include "FrameProcessor.h"
+
+class VideoAnalysis
+{
+private:
+  VideoCapture* videoCapture;
+  FrameProcessor* frameProcessor;
+  bool use_file;
+  std::string filename;
+  bool use_camera;
+  int cameraIndex;
+  bool use_comp;
+  long frameToStop;
+  std::string imgref;
+
+public:
+  VideoAnalysis();
+  ~VideoAnalysis();
+
+  bool setup(int argc, const char **argv);
+  void start();
+};
+
diff --git a/VideoCapture.cpp b/VideoCapture.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..895205376a3474c7b03a5e21de923b1352c62332
--- /dev/null
+++ b/VideoCapture.cpp
@@ -0,0 +1,275 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "VideoCapture.h"
+
+namespace VC_ROI
+{
+  IplImage* img_input1 = 0;
+  IplImage* img_input2 = 0;
+  int roi_x0 = 0;
+  int roi_y0 = 0;
+  int roi_x1 = 0;
+  int roi_y1 = 0;
+  int numOfRec = 0;
+  int startDraw = 0;
+  bool roi_defined = false;
+  bool use_roi = true;
+  bool disable_event = false;
+
+  void reset(void)
+  {
+    disable_event = false;
+    startDraw = false;
+  }
+
+  void VideoCapture_on_mouse(int evt, int x, int y, int flag, void* param)
+  {
+    if(use_roi == false || disable_event == true)
+      return;
+    
+    if(evt == CV_EVENT_LBUTTONDOWN)
+    {
+      if(!startDraw)
+      {
+        roi_x0 = x;
+        roi_y0 = y;
+        startDraw = 1;
+      }
+      else
+      {
+        roi_x1 = x;
+        roi_y1 = y;
+        startDraw = 0;
+        roi_defined = true;
+        disable_event = true;
+      }
+    }
+
+    if(evt == CV_EVENT_MOUSEMOVE && startDraw)
+    {
+      //redraw ROI selection
+      img_input2 = cvCloneImage(img_input1);
+      cvRectangle(img_input2, cvPoint(roi_x0,roi_y0), cvPoint(x,y), CV_RGB(255,0,0), 1);
+      cvShowImage("Input", img_input2);
+      cvReleaseImage(&img_input2);
+      //startDraw = false;
+      //disable_event = true;
+    }
+  }
+}
+
+VideoCapture::VideoCapture() : key(0), start_time(0), delta_time(0), freq(0), fps(0), frameNumber(0), stopAt(0),
+  useCamera(false), useVideo(false), input_resize_percent(100), showOutput(true), enableFlip(false)
+{
+  std::cout << "VideoCapture()" << std::endl;
+}
+
+VideoCapture::~VideoCapture()
+{
+  std::cout << "~VideoCapture()" << std::endl;
+}
+
+void VideoCapture::setFrameProcessor(IFrameProcessor* frameProcessorPtr)
+{
+  frameProcessor = frameProcessorPtr;
+}
+
+void VideoCapture::setCamera(int index)
+{
+  useCamera = true;
+  cameraIndex = index;
+
+  useVideo = false;
+}
+
+void VideoCapture::setUpCamera()
+{
+  std::cout << "Camera index:" << cameraIndex << std::endl;
+  capture = cvCaptureFromCAM(cameraIndex);
+
+  if(!capture)
+    std::cerr << "Cannot open initialize webcam!\n" << std::endl;
+}
+
+void VideoCapture::setVideo(std::string filename)
+{
+  useVideo = true;
+  videoFileName = filename;
+
+  useCamera = false;
+}
+
+void VideoCapture::setUpVideo()
+{
+  capture = cvCaptureFromFile(videoFileName.c_str());
+
+  if(!capture)
+    std::cerr << "Cannot open video file "<< videoFileName << std::endl;
+}
+
+void VideoCapture::start()
+{
+  loadConfig();
+
+  if(useCamera) setUpCamera();
+  if(useVideo)  setUpVideo();
+  if(!capture)  std::cerr << "Capture error..." << std::endl;
+  
+  int input_fps = cvGetCaptureProperty(capture,CV_CAP_PROP_FPS);
+  std::cout << "input->fps:" << input_fps << std::endl;
+
+  IplImage* frame1 = cvQueryFrame(capture);
+  frame = cvCreateImage(cvSize((int)((frame1->width*input_resize_percent)/100) , (int)((frame1->height*input_resize_percent)/100)), frame1->depth, frame1->nChannels);
+  //cvCreateImage(cvSize(frame1->width/input_resize_factor, frame1->height/input_resize_factor), frame1->depth, frame1->nChannels);
+  std::cout << "input->resize_percent:" << input_resize_percent << std::endl;
+  std::cout << "input->width:" << frame->width << std::endl;
+  std::cout << "input->height:" << frame->height << std::endl;
+
+  double loopDelay = 33.333;
+  if(input_fps > 0)
+    loopDelay = (1./input_fps)*1000.;
+  std::cout << "loopDelay:" << loopDelay << std::endl;
+
+  bool firstTime = true;
+  do
+  {
+    frameNumber++;
+
+    frame1 = cvQueryFrame(capture);
+    if(!frame1) break;
+
+    cvResize(frame1, frame);
+
+    if(enableFlip)
+      cvFlip(frame, frame, 0);
+    
+    if(VC_ROI::use_roi == true && VC_ROI::roi_defined == false && firstTime == true)
+    {
+      VC_ROI::reset();
+
+      do
+      {
+        cv::Mat img_input(frame);
+        
+        if(showOutput)
+        {
+          cv::imshow("Input", img_input);
+
+          std::cout << "Set ROI (press ESC to skip)" << std::endl;
+          VC_ROI::img_input1 = new IplImage(img_input);
+          cvSetMouseCallback("Input", VC_ROI::VideoCapture_on_mouse, NULL);
+          key = cvWaitKey(0);
+          delete VC_ROI::img_input1;
+        }
+        else
+          key = KEY_ESC;
+
+        if(key == KEY_ESC)
+        {
+          std::cout << "ROI disabled" << std::endl;
+          VC_ROI::reset();
+          VC_ROI::use_roi = false;
+          break;
+        }
+
+        if(VC_ROI::roi_defined)
+        {
+          std::cout << "ROI defined (" << VC_ROI::roi_x0 << "," << VC_ROI::roi_y0 << "," << VC_ROI::roi_x1 << "," << VC_ROI::roi_y1 << ")" << std::endl;
+          break;
+        }
+        else
+          std::cout << "ROI undefined" << std::endl;
+
+      }while(1);
+    }
+
+    if(VC_ROI::use_roi == true && VC_ROI::roi_defined == true)
+    {
+      CvRect rect = cvRect(VC_ROI::roi_x0, VC_ROI::roi_y0, VC_ROI::roi_x1 - VC_ROI::roi_x0, VC_ROI::roi_y1 - VC_ROI::roi_y0);
+      cvSetImageROI(frame, rect);
+    }
+
+    cv::Mat img_input(frame);
+    
+    if(showOutput)
+      cv::imshow("Input", img_input);
+
+    if(firstTime)
+      saveConfig();
+
+    start_time = cv::getTickCount();
+    frameProcessor->process(img_input);
+    int64 delta_time = cv::getTickCount() - start_time;
+    freq = cv::getTickFrequency();
+    fps = freq / delta_time;
+    //std::cout << "FPS: " << fps << std::endl;
+
+    cvResetImageROI(frame);
+
+    key = cvWaitKey(loopDelay);
+    //std::cout << "key: " << key << std::endl;
+
+    if(key == KEY_SPACE)
+      key = cvWaitKey(0);
+
+    if(key == KEY_ESC)
+      break;
+
+    if(stopAt > 0 && stopAt == frameNumber)
+      key = cvWaitKey(0);
+
+    firstTime = false;
+  }while(1);
+
+  cvReleaseCapture(&capture);
+}
+
+void VideoCapture::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/VideoCapture.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "stopAt", stopAt);
+  cvWriteInt(fs, "input_resize_percent", input_resize_percent);
+  cvWriteInt(fs, "enableFlip", enableFlip);
+  cvWriteInt(fs, "use_roi", VC_ROI::use_roi);
+  cvWriteInt(fs, "roi_defined", VC_ROI::roi_defined);
+  cvWriteInt(fs, "roi_x0", VC_ROI::roi_x0);
+  cvWriteInt(fs, "roi_y0", VC_ROI::roi_y0);
+  cvWriteInt(fs, "roi_x1", VC_ROI::roi_x1);
+  cvWriteInt(fs, "roi_y1", VC_ROI::roi_y1);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void VideoCapture::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/VideoCapture.xml", 0, CV_STORAGE_READ);
+
+  stopAt = cvReadIntByName(fs, 0, "stopAt", 0);
+  input_resize_percent = cvReadIntByName(fs, 0, "input_resize_percent", 100);
+  enableFlip = cvReadIntByName(fs, 0, "enableFlip", false);
+  VC_ROI::use_roi = cvReadIntByName(fs, 0, "use_roi", true);
+  VC_ROI::roi_defined = cvReadIntByName(fs, 0, "roi_defined", false);
+  VC_ROI::roi_x0 = cvReadIntByName(fs, 0, "roi_x0", 0);
+  VC_ROI::roi_y0 = cvReadIntByName(fs, 0, "roi_y0", 0);
+  VC_ROI::roi_x1 = cvReadIntByName(fs, 0, "roi_x1", 0);
+  VC_ROI::roi_y1 = cvReadIntByName(fs, 0, "roi_y1", 0);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/VideoCapture.h b/VideoCapture.h
new file mode 100644
index 0000000000000000000000000000000000000000..caf6f6cb91d241a13bd9cac491d45a4ddf3897d2
--- /dev/null
+++ b/VideoCapture.h
@@ -0,0 +1,63 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "Config.h"
+#include "IFrameProcessor.h"
+
+class VideoCapture
+{
+private:
+  IFrameProcessor* frameProcessor;
+  CvCapture* capture;
+  IplImage* frame;
+  int key;
+  int64 start_time;
+  int64 delta_time;
+  double freq;
+  double fps;
+  long frameNumber;
+  long stopAt;
+  bool useCamera;
+  int cameraIndex;
+  bool useVideo;
+  std::string videoFileName;
+  int input_resize_percent;
+  bool showOutput;
+  bool enableFlip;
+
+public:
+  VideoCapture();
+  ~VideoCapture();
+
+  void setFrameProcessor(IFrameProcessor* frameProcessorPtr);
+  void setCamera(int cameraIndex);
+  void setVideo(std::string filename);
+  void start();
+
+private:
+  void setUpCamera();
+  void setUpVideo();
+
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/bgslibrary_vs2010_opencv.txt b/bgslibrary_vs2010_opencv.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6ea8256e859b0a714e3dc1510ad285a7bfab12a2
--- /dev/null
+++ b/bgslibrary_vs2010_opencv.txt
@@ -0,0 +1,39 @@
+---------------------------------------------------
+BGSLibrary with Visual Studio 2010 and Opencv 2.4.5
+---------------------------------------------------
+
+1) Check our example project at [vs2010] folder
+http://code.google.com/p/bgslibrary/source/browse/trunk/vs2010
+
+
+Or configure manually by:
+
+
+1) Install OpenCV
+1.a) Download OpenCV 2.4.5 from http://opencv.org/
+2.b) Install in: C:\OpenCV2.4.5
+2.c) Add OpenCV binaries in your Path
+C:\OpenCV2.4.5\build\x86\vc10\bin
+
+2) Download BGSLibrary
+2.a) Checkout bgslibrary SVN at C:\bgslibrary
+
+3) Start Visual Studio 2010
+3.a) Create New Project
+3.b) Select Visual C++ -> Win32 -> Win32 Console Application
+3.c) Set project location: C:\bgslibrary
+3.d) Set project name: bgslibrary
+3.e) Set Empty project 
+3.f) Add Demo.cpp in [Source Files]
+3.g) Add content of c:\bgslibrary\package_bgs\*.* in [Header Files]
+3.h) Add content of c:\bgslibrary\package_analysis\*.* in [Header Files]
+3.i) Change to [Release] [Win32] mode
+3.j) Click on Project->Properties
+3.k) Change [Output Directory] to ..\
+3.l) Add OpenCV include in [C/C++] -> [Additional Include Directories]
+C:\OpenCV2.4.5\build\include;C:\OpenCV2.4.5\build\include\opencv;
+3.m) Add OpenCV libraries in [Linker]->[Input]
+C:\OpenCV2.4.5\build\x86\vc10\lib\*.lib
+3.n) Click in Build and wait
+3.o) Run C:\bgslibrary\bgslibrary.exe
+Enjoy!
\ No newline at end of file
diff --git a/config/FrameProcessor.xml b/config/FrameProcessor.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c76f826ebb87dd91db37552312138bf0f161fce3
--- /dev/null
+++ b/config/FrameProcessor.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<opencv_storage>
+<tictoc>""</tictoc>
+<enablePreProcessor>1</enablePreProcessor>
+<enableForegroundMaskAnalysis>0</enableForegroundMaskAnalysis>
+<enableFrameDifferenceBGS>1</enableFrameDifferenceBGS>
+<enableStaticFrameDifferenceBGS>0</enableStaticFrameDifferenceBGS>
+<enableWeightedMovingMeanBGS>0</enableWeightedMovingMeanBGS>
+<enableWeightedMovingVarianceBGS>0</enableWeightedMovingVarianceBGS>
+<enableMixtureOfGaussianV1BGS>0</enableMixtureOfGaussianV1BGS>
+<enableMixtureOfGaussianV2BGS>0</enableMixtureOfGaussianV2BGS>
+<enableAdaptiveBackgroundLearning>0</enableAdaptiveBackgroundLearning>
+<enableGMG>0</enableGMG>
+<enableDPAdaptiveMedianBGS>0</enableDPAdaptiveMedianBGS>
+<enableDPGrimsonGMMBGS>0</enableDPGrimsonGMMBGS>
+<enableDPZivkovicAGMMBGS>0</enableDPZivkovicAGMMBGS>
+<enableDPMeanBGS>0</enableDPMeanBGS>
+<enableDPWrenGABGS>0</enableDPWrenGABGS>
+<enableDPPratiMediodBGS>0</enableDPPratiMediodBGS>
+<enableDPEigenbackgroundBGS>0</enableDPEigenbackgroundBGS>
+<enableDPTextureBGS>0</enableDPTextureBGS>
+<enableT2FGMM_UM>0</enableT2FGMM_UM>
+<enableT2FGMM_UV>0</enableT2FGMM_UV>
+<enableT2FMRF_UM>0</enableT2FMRF_UM>
+<enableT2FMRF_UV>0</enableT2FMRF_UV>
+<enableFuzzySugenoIntegral>0</enableFuzzySugenoIntegral>
+<enableFuzzyChoquetIntegral>0</enableFuzzyChoquetIntegral>
+<enableLBSimpleGaussian>0</enableLBSimpleGaussian>
+<enableLBFuzzyGaussian>0</enableLBFuzzyGaussian>
+<enableLBMixtureOfGaussians>0</enableLBMixtureOfGaussians>
+<enableLBAdaptiveSOM>0</enableLBAdaptiveSOM>
+<enableLBFuzzyAdaptiveSOM>0</enableLBFuzzyAdaptiveSOM>
+<enableLbpMrf>0</enableLbpMrf>
+<enableMultiLayerBGS>0</enableMultiLayerBGS>
+<enablePBAS>0</enablePBAS>
+<enableVuMeter>0</enableVuMeter>
+<enableKDE>0</enableKDE>
+</opencv_storage>
diff --git a/config/PreProcessor.xml b/config/PreProcessor.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e58b3187a702e2b1fc36c4576aff75e7b7f4a9cb
--- /dev/null
+++ b/config/PreProcessor.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<opencv_storage>
+<equalizeHist>0</equalizeHist>
+<gaussianBlur>0</gaussianBlur>
+<enableShow>1</enableShow>
+</opencv_storage>
diff --git a/config/VideoCapture.xml b/config/VideoCapture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..60dd9aa81010d78759f5986f0aa5a2876da25f63
--- /dev/null
+++ b/config/VideoCapture.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<opencv_storage>
+<stopAt>0</stopAt>
+<input_resize_percent>100</input_resize_percent>
+<enableFlip>0</enableFlip>
+<use_roi>0</use_roi>
+<roi_defined>0</roi_defined>
+<roi_x0>0</roi_x0>
+<roi_y0>0</roi_y0>
+<roi_x1>0</roi_x1>
+<roi_y1>0</roi_y1>
+<showOutput>1</showOutput>
+</opencv_storage>
diff --git a/dataset/video.avi b/dataset/video.avi
new file mode 100644
index 0000000000000000000000000000000000000000..a29f00658be7d05b10344859e6bee9a501a7a2b1
Binary files /dev/null and b/dataset/video.avi differ
diff --git a/demos/DemoFrameDifferenceBGS.cpp b/demos/DemoFrameDifferenceBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f81242be085a5b6b150a4e5dc6f4cdf2c7a475f
--- /dev/null
+++ b/demos/DemoFrameDifferenceBGS.cpp
@@ -0,0 +1,49 @@
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "package_bgs/FrameDifferenceBGS.h"
+
+int main(int argc, char **argv)
+{
+  CvCapture *capture = 0;
+  
+  capture = cvCaptureFromCAM(0);
+  //capture = cvCaptureFromAVI("video.avi");
+  
+  if(!capture){
+    std::cerr << "Cannot open initialize webcam!" << std::endl;
+    return 1;
+  }
+  
+  IplImage *frame = cvQueryFrame(capture);
+  
+  FrameDifferenceBGS* bgs = new FrameDifferenceBGS;
+
+  int key = 0;
+  while(key != 'q')
+  {
+    frame = cvQueryFrame(capture);
+
+    if(!frame) break;
+
+    cv::Mat img_input(frame,true);
+    cv::resize(img_input,img_input,cv::Size(320,240));
+    cv::imshow("input", img_input);
+    
+    cv::Mat img_mask;
+    bgs->process(img_input, img_mask); // automatically shows the foreground mask image
+    
+    //if(!img_mask.empty())
+    //  do something
+    
+    key = cvWaitKey(1);
+  }
+
+  delete bgs;
+
+  cvDestroyAllWindows();
+  cvReleaseCapture(&capture);
+  
+  return 0;
+}
diff --git a/demos/DemoMultiLayerBGS.cpp b/demos/DemoMultiLayerBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf2bbad06817f9aebc14db2244e4cc09b29e4e42
--- /dev/null
+++ b/demos/DemoMultiLayerBGS.cpp
@@ -0,0 +1,49 @@
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "package_bgs/jmo/MultiLayerBGS.h"
+
+int main(int argc, char **argv)
+{
+  CvCapture *capture = 0;
+  
+  capture = cvCaptureFromCAM(0);
+  //capture = cvCaptureFromAVI("video.avi");
+  
+  if(!capture){
+    std::cerr << "Cannot open initialize webcam!" << std::endl;
+    return 1;
+  }
+  
+  IplImage *frame = cvQueryFrame(capture);
+  
+  MultiLayerBGS* bgs = new MultiLayerBGS;
+
+  int key = 0;
+  while(key != 'q')
+  {
+    frame = cvQueryFrame(capture);
+
+    if(!frame) break;
+
+    cv::Mat img_input(frame,true);
+    cv::resize(img_input,img_input,cv::Size(320,240));
+    cv::imshow("input", img_input);
+    
+    cv::Mat img_mask;
+    bgs->process(img_input, img_mask); // automatically shows the foreground mask image
+    
+    //if(!img_mask.empty())
+    //  do something
+    
+    key = cvWaitKey(1);
+  }
+
+  delete bgs;
+
+  cvDestroyAllWindows();
+  cvReleaseCapture(&capture);
+  
+  return 0;
+}
diff --git a/package_analysis/ForegroundMaskAnalysis.cpp b/package_analysis/ForegroundMaskAnalysis.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..45645a01e3feb98ce478cca89ef9754c29d99f52
--- /dev/null
+++ b/package_analysis/ForegroundMaskAnalysis.cpp
@@ -0,0 +1,101 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "ForegroundMaskAnalysis.h"
+
+ForegroundMaskAnalysis::ForegroundMaskAnalysis() : firstTime(true), stopAt(0), showOutput(true), img_ref_path("")
+{
+  std::cout << "ForegroundMaskAnalysis()" << std::endl;
+}
+
+ForegroundMaskAnalysis::~ForegroundMaskAnalysis()
+{
+  std::cout << "~ForegroundMaskAnalysis()" << std::endl;
+}
+
+void ForegroundMaskAnalysis::process(const long &frameNumber, const std::string &name, const cv::Mat &img_input)
+{
+  if(img_input.empty())
+    return;
+
+  if(stopAt == 0)
+  {
+    loadConfig();
+
+    if(firstTime)
+      saveConfig();
+  }
+
+  if(stopAt == frameNumber && img_ref_path.empty() == false)
+  {
+    cv::Mat img_ref = cv::imread(img_ref_path, 0);
+
+    if(showOutput)
+      cv::imshow("ForegroundMaskAnalysis", img_ref);
+
+    int rn = cv::countNonZero(img_ref);
+    cv::Mat i;
+    cv::Mat u;
+
+    if(rn > 0)
+    {
+      i = img_input & img_ref;
+      u = img_input | img_ref;
+    }
+    else
+    {
+      i = (~img_input) & (~img_ref);
+      u = (~img_input) | (~img_ref);
+    }
+
+    int in = cv::countNonZero(i);
+    int un = cv::countNonZero(u);
+    
+    double s = (((double)in) / ((double)un));
+    
+    if(showOutput)
+    {
+      cv::imshow("A^B", i);
+      cv::imshow("AvB", u);
+    }
+
+    std::cout << name << " - Similarity Measure: " << s << " press ENTER to continue" << std::endl;
+
+    cv::waitKey(0);
+  }
+
+  firstTime = false;
+}
+
+void ForegroundMaskAnalysis::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/ForegroundMaskAnalysis.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "stopAt", stopAt);
+  cvWriteString(fs, "img_ref_path", img_ref_path.c_str());
+  
+  cvReleaseFileStorage(&fs);
+}
+
+void ForegroundMaskAnalysis::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/ForegroundMaskAnalysis.xml", 0, CV_STORAGE_READ);
+  
+  stopAt = cvReadIntByName(fs, 0, "stopAt", 0);
+  img_ref_path = cvReadStringByName(fs, 0, "img_ref_path", "");
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_analysis/ForegroundMaskAnalysis.h b/package_analysis/ForegroundMaskAnalysis.h
new file mode 100644
index 0000000000000000000000000000000000000000..d6bfdaea123037b8b9b0d380910c84124a28204c
--- /dev/null
+++ b/package_analysis/ForegroundMaskAnalysis.h
@@ -0,0 +1,42 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <string>
+#include <cv.h>
+#include <highgui.h>
+
+class ForegroundMaskAnalysis
+{
+private:
+  bool firstTime;
+  bool showOutput;
+
+public:
+  ForegroundMaskAnalysis();
+  ~ForegroundMaskAnalysis();
+  
+  long stopAt;
+  std::string img_ref_path;
+
+  void process(const long &frameNumber, const std::string &name, const cv::Mat &img_input);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/AdaptiveBackgroundLearning.cpp b/package_bgs/AdaptiveBackgroundLearning.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b111e65be5ca7b12274af2f91dcd1672f1bd3e36
--- /dev/null
+++ b/package_bgs/AdaptiveBackgroundLearning.cpp
@@ -0,0 +1,111 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "AdaptiveBackgroundLearning.h"
+
+AdaptiveBackgroundLearning::AdaptiveBackgroundLearning() : firstTime(true), alpha(0.05), limit(-1), counter(0), minVal(0.0), maxVal(1.0), 
+  enableThreshold(true), threshold(15), showForeground(true), showBackground(true)
+{
+  std::cout << "AdaptiveBackgroundLearning()" << std::endl;
+}
+
+AdaptiveBackgroundLearning::~AdaptiveBackgroundLearning()
+{
+  std::cout << "~AdaptiveBackgroundLearning()" << std::endl;
+}
+
+void AdaptiveBackgroundLearning::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  if(img_background.empty())
+    img_input.copyTo(img_background);
+
+  cv::Mat img_input_f(img_input.size(), CV_32F);
+  img_input.convertTo(img_input_f, CV_32F, 1./255.);
+
+  cv::Mat img_background_f(img_background.size(), CV_32F);
+  img_background.convertTo(img_background_f, CV_32F, 1./255.);
+
+  cv::Mat img_diff_f(img_input.size(), CV_32F);
+  cv::absdiff(img_input_f, img_background_f, img_diff_f);
+
+  if((limit > 0 && limit < counter) || limit == -1)
+  {
+    img_background_f = alpha*img_input_f + (1-alpha)*img_background_f;
+    
+    cv::Mat img_new_background(img_input.size(), CV_8U);
+    img_background_f.convertTo(img_new_background, CV_8U, 255.0/(maxVal - minVal), -minVal);
+    img_new_background.copyTo(img_background);
+
+    if(limit > 0 && limit < counter)
+      counter++;
+  }
+  
+  cv::Mat img_foreground(img_input.size(), CV_8U);
+  img_diff_f.convertTo(img_foreground, CV_8U, 255.0/(maxVal - minVal), -minVal);
+
+  if(img_foreground.channels() == 3)
+    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+  
+  if(showForeground)
+    cv::imshow("A-Learning FG", img_foreground);
+
+  if(showBackground)
+    cv::imshow("A-Learning BG", img_background);
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void AdaptiveBackgroundLearning::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveBackgroundLearning.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "limit", limit);
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showForeground", showForeground);
+  cvWriteInt(fs, "showBackground", showBackground);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void AdaptiveBackgroundLearning::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveBackgroundLearning.xml", 0, CV_STORAGE_READ);
+  
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.05);
+  limit = cvReadIntByName(fs, 0, "limit", -1);
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showForeground = cvReadIntByName(fs, 0, "showForeground", true);
+  showBackground = cvReadIntByName(fs, 0, "showBackground", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/AdaptiveBackgroundLearning.h b/package_bgs/AdaptiveBackgroundLearning.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb07a643ecc09a3acee8dcc24d0f2e2f81fc1395
--- /dev/null
+++ b/package_bgs/AdaptiveBackgroundLearning.h
@@ -0,0 +1,50 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "IBGS.h"
+
+class AdaptiveBackgroundLearning : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Mat img_background;
+  double alpha;
+  long limit;
+  long counter;
+  double minVal;
+  double maxVal;
+  bool enableThreshold;
+  int threshold;
+  bool showForeground;
+  bool showBackground;
+
+public:
+  AdaptiveBackgroundLearning();
+  ~AdaptiveBackgroundLearning();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp b/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cd3e7d3d966ec6b2e2850d21305f15e1341889df
--- /dev/null
+++ b/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp
@@ -0,0 +1,131 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "AdaptiveSelectiveBackgroundLearning.h"
+
+AdaptiveSelectiveBackgroundLearning::AdaptiveSelectiveBackgroundLearning() : firstTime(true), 
+alphaLearn(0.05), alphaDetection(0.05), learningFrames(-1), counter(0), minVal(0.0), maxVal(1.0),
+threshold(15), showOutput(true)
+{
+  std::cout << "AdaptiveSelectiveBackgroundLearning()" << std::endl;
+}
+
+AdaptiveSelectiveBackgroundLearning::~AdaptiveSelectiveBackgroundLearning()
+{
+  std::cout << "~AdaptiveSelectiveBackgroundLearning()" << std::endl;
+}
+
+void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input_.empty())
+    return;
+
+  cv::Mat img_input;
+  if (img_input_.channels() == 3)
+    cv::cvtColor(img_input_, img_input, CV_BGR2GRAY);
+  else
+    img_input_.copyTo(img_input);
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  if(img_background.empty())
+    img_input.copyTo(img_background);
+
+  cv::Mat img_input_f(img_input.size(), CV_32F);
+  img_input.convertTo(img_input_f, CV_32F, 1./255.);
+
+  cv::Mat img_background_f(img_background.size(), CV_32F);
+  img_background.convertTo(img_background_f, CV_32F, 1./255.);
+
+  cv::Mat img_diff_f(img_input.size(), CV_32F);
+  cv::absdiff(img_input_f, img_background_f, img_diff_f);
+
+  cv::Mat img_foreground(img_input.size(), CV_8U);
+  img_diff_f.convertTo(img_foreground, CV_8U, 255.0 / (maxVal - minVal), -minVal);
+
+  cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+  cv::medianBlur(img_foreground, img_foreground, 3);
+
+  if (learningFrames > 0 && counter <= learningFrames)
+  {
+    //std::cout << "Adaptive update..." << std::endl;
+    // Only Adaptive update of the background model
+    img_background_f = alphaLearn * img_input_f + (1 - alphaLearn) * img_background_f;
+    counter++;
+  }
+  else
+  {
+    //std::cout << "Adaptive and Selective update..." << std::endl;
+    int rows = img_input.rows;
+    int cols = img_input.cols;
+
+    for (int i = 0; i < rows; i++)
+    {
+      for (int j = 0; j < cols; j++)
+      {
+        // Adaptive and Selective update of the background model
+        if (img_foreground.at<uchar>(i, j) == 0)
+        {
+          img_background_f.at<float>(i, j) = alphaDetection * img_input_f.at<float>(i, j) + (1 - alphaDetection) * img_background_f.at<float>(i, j);
+        }
+      }
+    }
+  }
+
+  cv::Mat img_new_background(img_input.size(), CV_8U);
+  img_background_f.convertTo(img_new_background, CV_8U, 255.0 / (maxVal - minVal), -minVal);
+  img_new_background.copyTo(img_background);
+  
+  if(showOutput)
+  {
+    cv::imshow("AS-Learning FG", img_foreground);
+    cv::imshow("AS-Learning BG", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void AdaptiveSelectiveBackgroundLearning::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveSelectiveBackgroundLearning.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "learningFrames", learningFrames);
+  cvWriteReal(fs, "alphaLearn", alphaLearn);
+  cvWriteReal(fs, "alphaDetection", alphaDetection);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void AdaptiveSelectiveBackgroundLearning::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveSelectiveBackgroundLearning.xml", 0, CV_STORAGE_READ);
+  
+  learningFrames = cvReadIntByName(fs, 0, "learningFrames", 90);
+  alphaLearn = cvReadRealByName(fs, 0, "alphaLearn", 0.05);
+  alphaDetection = cvReadRealByName(fs, 0, "alphaDetection", 0.05);
+  threshold = cvReadIntByName(fs, 0, "threshold", 25);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/AdaptiveSelectiveBackgroundLearning.h b/package_bgs/AdaptiveSelectiveBackgroundLearning.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb9f4d57320be6c0e4df50808af576ff4f869772
--- /dev/null
+++ b/package_bgs/AdaptiveSelectiveBackgroundLearning.h
@@ -0,0 +1,49 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "IBGS.h"
+
+class AdaptiveSelectiveBackgroundLearning : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Mat img_background;
+  double alphaLearn;
+  double alphaDetection;
+  long learningFrames;
+  long counter;
+  double minVal;
+  double maxVal;
+  int threshold;
+  bool showOutput;
+
+public:
+  AdaptiveSelectiveBackgroundLearning();
+  ~AdaptiveSelectiveBackgroundLearning();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/FrameDifferenceBGS.cpp b/package_bgs/FrameDifferenceBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e87165120919861a03b54fd8066b073122bfdf59
--- /dev/null
+++ b/package_bgs/FrameDifferenceBGS.cpp
@@ -0,0 +1,83 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "FrameDifferenceBGS.h"
+
+FrameDifferenceBGS::FrameDifferenceBGS() : firstTime(true), enableThreshold(true), threshold(15), showOutput(true)
+{
+  std::cout << "FrameDifferenceBGS()" << std::endl;
+}
+
+FrameDifferenceBGS::~FrameDifferenceBGS()
+{
+  std::cout << "~FrameDifferenceBGS()" << std::endl;
+}
+
+void FrameDifferenceBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  if(img_input_prev.empty())
+  {
+    img_input.copyTo(img_input_prev);
+    return;
+  }
+
+  cv::absdiff(img_input_prev, img_input, img_foreground);
+
+  if(img_foreground.channels() == 3)
+    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+
+  if(showOutput)
+    cv::imshow("Frame Difference", img_foreground);
+
+  img_foreground.copyTo(img_output);
+
+  img_input.copyTo(img_input_prev);
+
+  firstTime = false;
+}
+
+void FrameDifferenceBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FrameDifferenceBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void FrameDifferenceBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FrameDifferenceBGS.xml", 0, CV_STORAGE_READ);
+  
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/FrameDifferenceBGS.h b/package_bgs/FrameDifferenceBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fab44d1f8250be50d62b5dd7a3662b2567e7b54
--- /dev/null
+++ b/package_bgs/FrameDifferenceBGS.h
@@ -0,0 +1,44 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "IBGS.h"
+
+class FrameDifferenceBGS : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Mat img_input_prev;
+  cv::Mat img_foreground;
+  bool enableThreshold;
+  int threshold;
+  bool showOutput;
+
+public:
+  FrameDifferenceBGS();
+  ~FrameDifferenceBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/GMG.cpp b/package_bgs/GMG.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..675b23cba8f3a9f71a35bc99fa66d95c7094b456
--- /dev/null
+++ b/package_bgs/GMG.cpp
@@ -0,0 +1,99 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "GMG.h"
+
+GMG::GMG() : firstTime(true), initializationFrames(20), decisionThreshold(0.7), showOutput(true)
+{
+  std::cout << "GMG()" << std::endl;
+
+  cv::initModule_video();
+  cv::setUseOptimized(true);
+  cv::setNumThreads(8);
+
+  fgbg = cv::Algorithm::create<cv::BackgroundSubtractorGMG>("BackgroundSubtractor.GMG");
+}
+
+GMG::~GMG()
+{
+  std::cout << "~GMG()" << std::endl;
+}
+
+void GMG::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    fgbg->set("initializationFrames", initializationFrames);
+    fgbg->set("decisionThreshold", decisionThreshold);
+
+    saveConfig();
+  }
+  
+  if(fgbg.empty())
+  {
+    std::cerr << "Failed to create BackgroundSubtractor.GMG Algorithm." << std::endl;
+    return;
+  }
+
+  (*fgbg)(img_input, img_foreground);
+
+  cv::Mat img_background;
+  (*fgbg).getBackgroundImage(img_background);
+
+  img_input.copyTo(img_segmentation);
+  cv::add(img_input, cv::Scalar(100, 100, 0), img_segmentation, img_foreground);
+
+  if(showOutput)
+  {
+    if (!img_foreground.empty())
+      cv::imshow("GMG FG (Godbehere-Matsukawa-Goldberg)", img_foreground);
+    
+    if (!img_background.empty())
+      cv::imshow("GMG BG (Godbehere-Matsukawa-Goldberg)", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void GMG::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/GMG.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "initializationFrames", initializationFrames);
+  cvWriteReal(fs, "decisionThreshold", decisionThreshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void GMG::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/GMG.xml", 0, CV_STORAGE_READ);
+  
+  initializationFrames = cvReadIntByName(fs, 0, "initializationFrames", 20);
+  decisionThreshold = cvReadRealByName(fs, 0, "decisionThreshold", 0.7);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+  
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/GMG.h b/package_bgs/GMG.h
new file mode 100644
index 0000000000000000000000000000000000000000..9da28adb7a40d2cb443d34372a6e6220c09f3af3
--- /dev/null
+++ b/package_bgs/GMG.h
@@ -0,0 +1,45 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <opencv2/opencv.hpp>
+
+#include "IBGS.h"
+
+class GMG : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Ptr<cv::BackgroundSubtractorGMG> fgbg;
+  int initializationFrames;
+  double decisionThreshold;
+  cv::Mat img_foreground;
+  cv::Mat img_segmentation;
+  bool showOutput;
+
+public:
+  GMG();
+  ~GMG();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/IBGS.h b/package_bgs/IBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b57658660950d70bc6902bcfbfeea4bee5cd695
--- /dev/null
+++ b/package_bgs/IBGS.h
@@ -0,0 +1,33 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <cv.h>
+
+class IBGS
+{
+public:
+  virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground, cv::Mat &img_background) = 0;
+  /*virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground){
+    process(img_input, img_foreground, cv::Mat());
+  }*/
+  virtual ~IBGS(){}
+
+private:
+  virtual void saveConfig() = 0;
+  virtual void loadConfig() = 0;
+};
diff --git a/package_bgs/MixtureOfGaussianV1BGS.cpp b/package_bgs/MixtureOfGaussianV1BGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..51d41eb57348d76695a5c6c4392dc0e5e385a371
--- /dev/null
+++ b/package_bgs/MixtureOfGaussianV1BGS.cpp
@@ -0,0 +1,95 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "MixtureOfGaussianV1BGS.h"
+
+MixtureOfGaussianV1BGS::MixtureOfGaussianV1BGS() : firstTime(true), alpha(0.05), enableThreshold(true), threshold(15), showOutput(true)
+{
+  std::cout << "MixtureOfGaussianV1BGS()" << std::endl;
+}
+
+MixtureOfGaussianV1BGS::~MixtureOfGaussianV1BGS()
+{
+  std::cout << "~MixtureOfGaussianV1BGS()" << std::endl;
+}
+
+void MixtureOfGaussianV1BGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  //------------------------------------------------------------------
+  // BackgroundSubtractorMOG
+  // http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog
+  //
+  // Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm.
+  //
+  // The class implements the algorithm described in:
+  //   P. KadewTraKuPong and R. Bowden, 
+  //   An improved adaptive background mixture model for real-time tracking with shadow detection, 
+  //   Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001
+  //------------------------------------------------------------------
+
+  mog(img_input, img_foreground, alpha);
+  cv::Mat img_background;
+  mog.getBackgroundImage(img_background);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+
+  if(showOutput)
+  {
+    if (!img_foreground.empty())
+      cv::imshow("GMM FG (KadewTraKuPong&Bowden)", img_foreground);
+    
+    if (!img_background.empty())
+      cv::imshow("GMM BG (KadewTraKuPong&Bowden)", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void MixtureOfGaussianV1BGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV1BGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void MixtureOfGaussianV1BGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV1BGS.xml", 0, CV_STORAGE_READ);
+  
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.05);
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/MixtureOfGaussianV1BGS.h b/package_bgs/MixtureOfGaussianV1BGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a67acc27fbb9859d6fd2b60a5dd1ea15d0ffcb4
--- /dev/null
+++ b/package_bgs/MixtureOfGaussianV1BGS.h
@@ -0,0 +1,47 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+#include <opencv2/video/background_segm.hpp>
+
+#include "IBGS.h"
+
+class MixtureOfGaussianV1BGS : public IBGS
+{
+private:
+  bool firstTime;
+  cv::BackgroundSubtractorMOG mog;
+  cv::Mat img_foreground;
+  double alpha;
+  bool enableThreshold;
+  int threshold;
+  bool showOutput;
+
+public:
+  MixtureOfGaussianV1BGS();
+  ~MixtureOfGaussianV1BGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/MixtureOfGaussianV2BGS.cpp b/package_bgs/MixtureOfGaussianV2BGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ce33a3ef1b36a5948c20288530be22332106f0c
--- /dev/null
+++ b/package_bgs/MixtureOfGaussianV2BGS.cpp
@@ -0,0 +1,98 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "MixtureOfGaussianV2BGS.h"
+
+MixtureOfGaussianV2BGS::MixtureOfGaussianV2BGS() : firstTime(true), alpha(0.05), enableThreshold(true), threshold(15), showOutput(true)
+{
+  std::cout << "MixtureOfGaussianV2BGS()" << std::endl;
+}
+
+MixtureOfGaussianV2BGS::~MixtureOfGaussianV2BGS()
+{
+  std::cout << "~MixtureOfGaussianV2BGS()" << std::endl;
+}
+
+void MixtureOfGaussianV2BGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  //------------------------------------------------------------------
+  // BackgroundSubtractorMOG2
+  // http://opencv.itseez.com/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractormog2
+  //
+  // Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm.
+  //
+  // The class implements the Gaussian mixture model background subtraction described in:
+  //  (1) Z.Zivkovic, Improved adaptive Gausian mixture model for background subtraction, International Conference Pattern Recognition, UK, August, 2004, 
+  //  The code is very fast and performs also shadow detection. Number of Gausssian components is adapted per pixel.
+  //
+  //  (2) Z.Zivkovic, F. van der Heijden, Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction, 
+  //  Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. 
+  //  The algorithm similar to the standard Stauffer&Grimson algorithm with additional selection of the number of the Gaussian components based on: 
+  //    Z.Zivkovic, F.van der Heijden, Recursive unsupervised learning of finite mixture models, IEEE Trans. on Pattern Analysis and Machine Intelligence, 
+  //    vol.26, no.5, pages 651-656, 2004.
+  //------------------------------------------------------------------
+
+  mog(img_input, img_foreground, alpha);
+  
+  cv::Mat img_background;
+  mog.getBackgroundImage(img_background);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+
+  if(showOutput)
+  {
+    cv::imshow("GMM (Zivkovic&Heijden)", img_foreground);
+    cv::imshow("GMM BKG (Zivkovic&Heijden)", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void MixtureOfGaussianV2BGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV2BGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void MixtureOfGaussianV2BGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV2BGS.xml", 0, CV_STORAGE_READ);
+  
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.05);
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/MixtureOfGaussianV2BGS.h b/package_bgs/MixtureOfGaussianV2BGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..495d70128f183df709a60d030916a48543af96b3
--- /dev/null
+++ b/package_bgs/MixtureOfGaussianV2BGS.h
@@ -0,0 +1,47 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+#include <opencv2/video/background_segm.hpp>
+
+#include "IBGS.h"
+
+class MixtureOfGaussianV2BGS : public IBGS
+{
+private:
+  bool firstTime;
+  cv::BackgroundSubtractorMOG2 mog;
+  cv::Mat img_foreground;
+  double alpha;
+  bool enableThreshold;
+  int threshold;
+  bool showOutput;
+
+public:
+  MixtureOfGaussianV2BGS();
+  ~MixtureOfGaussianV2BGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/StaticFrameDifferenceBGS.cpp b/package_bgs/StaticFrameDifferenceBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3463c457b2ae509560903d76d46ff8d2a61daf5d
--- /dev/null
+++ b/package_bgs/StaticFrameDifferenceBGS.cpp
@@ -0,0 +1,79 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "StaticFrameDifferenceBGS.h"
+
+StaticFrameDifferenceBGS::StaticFrameDifferenceBGS() : firstTime(true), enableThreshold(true), threshold(15), showOutput(true)
+{
+  std::cout << "StaticFrameDifferenceBGS()" << std::endl;
+}
+
+StaticFrameDifferenceBGS::~StaticFrameDifferenceBGS()
+{
+  std::cout << "~StaticFrameDifferenceBGS()" << std::endl;
+}
+
+void StaticFrameDifferenceBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  if(img_background.empty())
+    img_input.copyTo(img_background);
+  
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  cv::absdiff(img_input, img_background, img_foreground);
+
+  if(img_foreground.channels() == 3)
+    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+
+  if(showOutput)
+    cv::imshow("Static Frame Difference", img_foreground);
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  firstTime = false;
+}
+
+void StaticFrameDifferenceBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/StaticFrameDifferenceBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void StaticFrameDifferenceBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/StaticFrameDifferenceBGS.xml", 0, CV_STORAGE_READ);
+  
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/StaticFrameDifferenceBGS.h b/package_bgs/StaticFrameDifferenceBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..416d13be3a4fc21fffe7bd86ab155b978499a3c2
--- /dev/null
+++ b/package_bgs/StaticFrameDifferenceBGS.h
@@ -0,0 +1,45 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "IBGS.h"
+
+class StaticFrameDifferenceBGS : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Mat img_background;
+  cv::Mat img_foreground;
+  bool enableThreshold;
+  int threshold;
+  bool showOutput;
+
+public:
+  StaticFrameDifferenceBGS();
+  ~StaticFrameDifferenceBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/WeightedMovingMeanBGS.cpp b/package_bgs/WeightedMovingMeanBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..841c467393c3012aff42eac1a36b44321b024b80
--- /dev/null
+++ b/package_bgs/WeightedMovingMeanBGS.cpp
@@ -0,0 +1,122 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "WeightedMovingMeanBGS.h"
+
+WeightedMovingMeanBGS::WeightedMovingMeanBGS() : firstTime(true), enableWeight(true), enableThreshold(true), threshold(15), showOutput(true), showBackground(false)
+{
+  std::cout << "WeightedMovingMeanBGS()" << std::endl;
+}
+
+WeightedMovingMeanBGS::~WeightedMovingMeanBGS()
+{
+  std::cout << "~WeightedMovingMeanBGS()" << std::endl;
+}
+
+void WeightedMovingMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  if(img_input_prev_1.empty())
+  {
+    img_input.copyTo(img_input_prev_1);
+    return;
+  }
+
+  if(img_input_prev_2.empty())
+  {
+    img_input_prev_1.copyTo(img_input_prev_2);
+    img_input.copyTo(img_input_prev_1);
+    return;
+  }
+  
+  cv::Mat img_input_f(img_input.size(), CV_32F);
+  img_input.convertTo(img_input_f, CV_32F, 1./255.);
+
+  cv::Mat img_input_prev_1_f(img_input.size(), CV_32F);
+  img_input_prev_1.convertTo(img_input_prev_1_f, CV_32F, 1./255.);
+
+  cv::Mat img_input_prev_2_f(img_input.size(), CV_32F);
+  img_input_prev_2.convertTo(img_input_prev_2_f, CV_32F, 1./255.);
+
+  cv::Mat img_background_f(img_input.size(), CV_32F);
+  
+  if(enableWeight)
+    img_background_f = ((img_input_f * 0.5) + (img_input_prev_1_f * 0.3) + (img_input_prev_2_f * 0.2));
+  else
+    img_background_f = ((img_input_f) + (img_input_prev_1_f) + (img_input_prev_2_f)) / 3.0;
+
+  cv::Mat img_background(img_background_f.size(), CV_8U);
+
+  double minVal, maxVal;
+  minVal = 0.; maxVal = 1.;
+  img_background_f.convertTo(img_background, CV_8U, 255.0/(maxVal - minVal), -minVal);
+  
+  if(showBackground)
+    cv::imshow("W Moving Mean BG Model", img_background);
+
+  cv::Mat img_foreground;
+  cv::absdiff(img_input, img_background, img_foreground);
+
+  if(img_foreground.channels() == 3)
+    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+
+  if(showOutput)
+    cv::imshow("W Moving Mean FG Mask", img_foreground);
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  img_input_prev_1.copyTo(img_input_prev_2);
+  img_input.copyTo(img_input_prev_1);
+
+  firstTime = false;
+}
+
+void WeightedMovingMeanBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingMeanBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "enableWeight", enableWeight);
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+  cvWriteInt(fs, "showBackground", showBackground);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void WeightedMovingMeanBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingMeanBGS.xml", 0, CV_STORAGE_READ);
+  
+  enableWeight = cvReadIntByName(fs, 0, "enableWeight", true);
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+  showBackground = cvReadIntByName(fs, 0, "showBackground", false);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/WeightedMovingMeanBGS.h b/package_bgs/WeightedMovingMeanBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6684e7ab8cb866ae4517fab27707e8004d2ae14
--- /dev/null
+++ b/package_bgs/WeightedMovingMeanBGS.h
@@ -0,0 +1,47 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "IBGS.h"
+
+class WeightedMovingMeanBGS : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Mat img_input_prev_1;
+  cv::Mat img_input_prev_2;
+  bool enableWeight;
+  bool enableThreshold;
+  int threshold;
+  bool showOutput;
+  bool showBackground;
+
+public:
+  WeightedMovingMeanBGS();
+  ~WeightedMovingMeanBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/WeightedMovingVarianceBGS.cpp b/package_bgs/WeightedMovingVarianceBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e691e9e470ffa42236c4a6408f3d9703c904798
--- /dev/null
+++ b/package_bgs/WeightedMovingVarianceBGS.cpp
@@ -0,0 +1,161 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "WeightedMovingVarianceBGS.h"
+
+WeightedMovingVarianceBGS::WeightedMovingVarianceBGS() : firstTime(true), enableWeight(true), 
+  enableThreshold(true), threshold(15), showOutput(true)
+{
+  std::cout << "WeightedMovingVarianceBGS()" << std::endl;
+}
+
+WeightedMovingVarianceBGS::~WeightedMovingVarianceBGS()
+{
+  std::cout << "~WeightedMovingVarianceBGS()" << std::endl;
+}
+
+void WeightedMovingVarianceBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  if(img_input_prev_1.empty())
+  {
+    img_input.copyTo(img_input_prev_1);
+    return;
+  }
+
+  if(img_input_prev_2.empty())
+  {
+    img_input_prev_1.copyTo(img_input_prev_2);
+    img_input.copyTo(img_input_prev_1);
+    return;
+  }
+
+  cv::Mat img_input_f(img_input.size(), CV_32F);
+  img_input.convertTo(img_input_f, CV_32F, 1./255.);
+
+  cv::Mat img_input_prev_1_f(img_input.size(), CV_32F);
+  img_input_prev_1.convertTo(img_input_prev_1_f, CV_32F, 1./255.);
+
+  cv::Mat img_input_prev_2_f(img_input.size(), CV_32F);
+  img_input_prev_2.convertTo(img_input_prev_2_f, CV_32F, 1./255.);
+
+  cv::Mat img_foreground;
+
+  // Weighted mean
+  cv::Mat img_mean_f(img_input.size(), CV_32F);
+  
+  if(enableWeight)
+    img_mean_f = ((img_input_f * 0.5) + (img_input_prev_1_f * 0.3) + (img_input_prev_2_f * 0.2));
+  else
+    img_mean_f = ((img_input_f * 0.3) + (img_input_prev_1_f * 0.3) + (img_input_prev_2_f * 0.3));
+  
+  // Weighted variance
+  cv::Mat img_1_f(img_input.size(), CV_32F);
+  cv::Mat img_2_f(img_input.size(), CV_32F);
+  cv::Mat img_3_f(img_input.size(), CV_32F);
+  cv::Mat img_4_f(img_input.size(), CV_32F);
+
+  if(enableWeight)
+  {
+    img_1_f = computeWeightedVariance(img_input_f, img_mean_f, 0.5);
+    img_2_f = computeWeightedVariance(img_input_prev_1_f, img_mean_f, 0.3);
+    img_3_f = computeWeightedVariance(img_input_prev_2_f, img_mean_f, 0.2);
+    img_4_f = (img_1_f + img_2_f + img_3_f);
+  }
+  else
+  {
+    img_1_f = computeWeightedVariance(img_input_f, img_mean_f, 0.3);
+    img_2_f = computeWeightedVariance(img_input_prev_1_f, img_mean_f, 0.3);
+    img_3_f = computeWeightedVariance(img_input_prev_2_f, img_mean_f, 0.3);
+    img_4_f = (img_1_f + img_2_f + img_3_f);
+  }
+  
+  // Standard deviation
+  cv::Mat img_sqrt_f(img_input.size(), CV_32F);
+  cv::sqrt(img_4_f, img_sqrt_f);
+  cv::Mat img_sqrt(img_input.size(), CV_8U);
+  double minVal, maxVal;
+  minVal = 0.; maxVal = 1.;
+  img_sqrt_f.convertTo(img_sqrt, CV_8U, 255.0/(maxVal - minVal), -minVal);
+  img_sqrt.copyTo(img_foreground);
+
+  if(img_foreground.channels() == 3)
+    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
+
+  if(enableThreshold)
+    cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY);
+
+  if(showOutput)
+    cv::imshow("W Moving Variance", img_foreground);
+
+  img_foreground.copyTo(img_output);
+
+  img_input_prev_1.copyTo(img_input_prev_2);
+  img_input.copyTo(img_input_prev_1);
+  
+  firstTime = false;
+}
+
+//unused
+cv::Mat WeightedMovingVarianceBGS::computeWeightedMean(const std::vector<cv::Mat> &v_img_input_f, const std::vector<double> weights)
+{
+  cv::Mat img;
+  return img;
+}
+
+cv::Mat WeightedMovingVarianceBGS::computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight)
+{
+  //ERROR in return (weight * ((cv::abs(img_input_f - img_mean_f))^2.));
+  
+  cv::Mat img_f_absdiff(img_input_f.size(), CV_32F);
+  cv::absdiff(img_input_f, img_mean_f, img_f_absdiff);
+  cv::Mat img_f_pow(img_input_f.size(), CV_32F);
+  cv::pow(img_f_absdiff, 2.0, img_f_pow);
+  cv::Mat img_f = weight * img_f_pow;
+  
+  return img_f;
+}
+
+void WeightedMovingVarianceBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingVarianceBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "enableWeight", enableWeight);
+  cvWriteInt(fs, "enableThreshold", enableThreshold);
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "showOutput", showOutput);
+  
+  cvReleaseFileStorage(&fs);
+}
+
+void WeightedMovingVarianceBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingVarianceBGS.xml", 0, CV_STORAGE_READ);
+  
+  enableWeight = cvReadIntByName(fs, 0, "enableWeight", true);
+  enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true);
+  threshold = cvReadIntByName(fs, 0, "threshold", 15);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+  
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/WeightedMovingVarianceBGS.h b/package_bgs/WeightedMovingVarianceBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..f07cf592fcecdc33c115e2e391b5ce55f5f70910
--- /dev/null
+++ b/package_bgs/WeightedMovingVarianceBGS.h
@@ -0,0 +1,48 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "IBGS.h"
+
+class WeightedMovingVarianceBGS : public IBGS
+{
+private:
+  bool firstTime;
+  cv::Mat img_input_prev_1;
+  cv::Mat img_input_prev_2;
+  bool enableWeight;
+  bool enableThreshold;
+  int threshold;
+  bool showOutput;
+
+public:
+  WeightedMovingVarianceBGS();
+  ~WeightedMovingVarianceBGS();
+
+  cv::Mat computeWeightedMean(const std::vector<cv::Mat> &v_img_input_f, const std::vector<double> weights);
+  cv::Mat computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight);
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/package_bgs/ae/KDE.cpp b/package_bgs/ae/KDE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2cbbd8c808066f8a6c30c7dc31f6ed90068caa84
--- /dev/null
+++ b/package_bgs/ae/KDE.cpp
@@ -0,0 +1,128 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "KDE.h"
+
+KDE::KDE() : SequenceLength(50), TimeWindowSize(100), SDEstimationFlag(1), lUseColorRatiosFlag(1),
+  th(10e-8), alpha(0.3), framesToLearn(10), frameNumber(0), firstTime(true), showOutput(true)
+{
+  p = new NPBGSubtractor;
+  std::cout << "KDE()" << std::endl;
+}
+
+KDE::~KDE()
+{
+  delete FGImage;
+  delete p;
+  std::cout << "~KDE()" << std::endl;
+}
+
+void KDE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    rows = img_input.size().height;
+    cols = img_input.size().width;
+    color_channels = img_input.channels();
+
+    // SequenceLength: number of samples for each pixel.
+    // TimeWindowSize: Time window for sampling. for example in the call above, the bg will sample 50 points out of 100 frames. 
+    // this rate will affect how fast the model adapt.
+    // SDEstimationFlag: True means to estimate suitable kernel bandwidth to each pixel, False uses a default value.
+    // lUseColorRatiosFlag: True means use normalized RGB for color (recommended.)
+    p->Intialize(rows,cols,color_channels,SequenceLength,TimeWindowSize,SDEstimationFlag,lUseColorRatiosFlag);
+    // th: 0-1 is the probability threshold for a pixel to be a foregroud. typically make it small as 10e-8. the smaller the value the less false positive and more false negative.
+    // alpha: 0-1, for color. typically set to 0.3. this affect shadow suppression.
+    p->SetThresholds(th,alpha);
+
+    FGImage = new unsigned char[rows*cols];
+    //FilteredFGImage = new unsigned char[rows*cols];
+    FilteredFGImage = 0;
+    DisplayBuffers = 0;
+
+    img_foreground = cv::Mat::zeros(rows,cols,CV_8UC1);
+
+    frameNumber = 0;
+    saveConfig();
+    firstTime = false;
+  }
+
+  // Stores the first N frames to build the background model
+  if(frameNumber < framesToLearn)
+  {
+    p->AddFrame(img_input.data);
+    frameNumber++;
+    return;
+  }
+
+  // Build the background model with first 10 frames
+  if(frameNumber == framesToLearn)
+  {
+    p->Estimation();
+    frameNumber++;
+  }
+
+  // Now, we can subtract the background
+  ((NPBGSubtractor *)p)->NBBGSubtraction(img_input.data,FGImage,FilteredFGImage,DisplayBuffers);
+  
+  // At each frame also you can call the update function to adapt the bg
+  // here you pass a mask where pixels with true value will be masked out of the update.
+  ((NPBGSubtractor *)p)->Update(FGImage);
+
+  img_foreground.data = FGImage;
+
+  if(showOutput)
+    cv::imshow("KDE", img_foreground);
+
+  img_foreground.copyTo(img_output);
+}
+
+void KDE::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/KDE.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "framesToLearn", framesToLearn);
+  cvWriteInt(fs, "SequenceLength", SequenceLength);
+  cvWriteInt(fs, "TimeWindowSize", TimeWindowSize);
+  cvWriteInt(fs, "SDEstimationFlag", SDEstimationFlag);
+  cvWriteInt(fs, "lUseColorRatiosFlag", lUseColorRatiosFlag);
+  cvWriteReal(fs, "th", th);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void KDE::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/KDE.xml", 0, CV_STORAGE_READ);
+  
+  framesToLearn = cvReadIntByName(fs, 0, "framesToLearn", 10);
+  SequenceLength = cvReadIntByName(fs, 0, "SequenceLength", 50);
+  TimeWindowSize = cvReadIntByName(fs, 0, "TimeWindowSize", 100);
+  SDEstimationFlag = cvReadIntByName(fs, 0, "SDEstimationFlag", 1);
+  lUseColorRatiosFlag = cvReadIntByName(fs, 0, "lUseColorRatiosFlag", 1);
+  th = cvReadRealByName(fs, 0, "th", 10e-8);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/ae/KDE.h b/package_bgs/ae/KDE.h
new file mode 100644
index 0000000000000000000000000000000000000000..39f01dc196d57245faef08b88b2d2b6a5d9367d1
--- /dev/null
+++ b/package_bgs/ae/KDE.h
@@ -0,0 +1,58 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "NPBGSubtractor.h"
+#include "../IBGS.h"
+
+class KDE : public IBGS
+{
+private:
+  NPBGSubtractor *p;
+  int rows;
+  int cols;
+  int color_channels;
+  int SequenceLength;
+  int TimeWindowSize;
+  int SDEstimationFlag;
+  int lUseColorRatiosFlag;
+  double th;
+  double alpha;
+  int framesToLearn;
+  int frameNumber;
+  bool firstTime;
+  bool showOutput;
+
+  cv::Mat img_foreground;
+  unsigned char *FGImage;
+  unsigned char *FilteredFGImage;
+  unsigned char **DisplayBuffers;
+
+public:
+  KDE();
+  ~KDE();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+  
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/package_bgs/ae/KernelTable.cpp b/package_bgs/ae/KernelTable.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9e20d7cfc0c09382bc360bda5b069aa870c39d98
--- /dev/null
+++ b/package_bgs/ae/KernelTable.cpp
@@ -0,0 +1,116 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*
+* Copyright 2001 by Ahmed Elgammal All  rights reserved.
+*
+* Permission to use, copy,  or modify this software and  its documentation
+* for  educational  and  research purposes only and without fee  is hereby
+* granted, provided  that this copyright notice and the original authors's
+* name appear  on all copies and supporting documentation.  If individual
+* files are  separated from  this  distribution directory  structure, this
+* copyright notice must be included.  For any other uses of this software,
+* in original or  modified form, including but not limited to distribution
+* in whole or in  part, specific  prior permission  must be  obtained from
+* Author or UMIACS.  These programs shall not  be  used, rewritten, or  
+* adapted as  the basis  of  a commercial  software  or  hardware product 
+* without first obtaining appropriate licenses  from Author. 
+* Other than these cases, no part of this software may be used or
+* distributed without written permission of the author.
+*
+* Neither the author nor UMIACS make any representations about the 
+* suitability of this software for any purpose.  It is provided 
+* "as is" without express or implied warranty.
+*
+* Ahmed Elgammal
+* 
+* University of Maryland at College Park
+* UMIACS
+* A.V. Williams Bldg. 
+* CollegePark, MD 20742
+* E-mail:  elgammal@umiacs.umd.edu
+*
+**/
+
+#include "KernelTable.h"
+#include <math.h>
+
+#define PI 3.14159
+
+KernelLUTable::KernelLUTable()
+{
+  std::cout << "KernelLUTable()" << std::endl;
+}
+
+KernelLUTable::~KernelLUTable()
+{
+  delete kerneltable;
+  delete kernelsums;
+  std::cout << "~KernelLUTable()" << std::endl;
+}
+
+KernelLUTable::KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins)
+{
+  std::cout << "KernelLUTable()" << std::endl;
+
+  double C1,C2,v,segma,sum;
+  int bin,b;
+
+  minsegma = Segmamin;
+  maxsegma = Segmamax;
+  segmabins = Segmabins;
+  tablehalfwidth = KernelHalfWidth;
+
+  // Generate the Kernel
+
+  // allocate memory for the Kernal Table
+  kerneltable = new double[segmabins*(2*KernelHalfWidth+1)];
+  kernelsums = new double[segmabins];
+
+  double segmastep = (maxsegma - minsegma) / segmabins;
+  double y;
+
+  for(segma = minsegma, bin = 0; bin < segmabins; segma += segmastep, bin++) 
+  {
+    C1 = 1/(sqrt(2*PI)*segma);
+    C2 = -1/(2*segma*segma);
+
+    b = (2*KernelHalfWidth+1)*bin;
+    sum = 0;
+    
+    for(int x = 0; x <= KernelHalfWidth; x++)
+    {
+      y = x/1.0;
+      v = C1*exp(C2*y*y);
+      kerneltable[b+KernelHalfWidth+x]=v;
+      kerneltable[b+KernelHalfWidth-x]=v;
+      sum += 2*v;
+    }
+
+    sum -= C1;
+
+    kernelsums[bin] = sum;
+
+    // Normailization
+    for(int x = 0; x <= KernelHalfWidth; x++)
+    {
+      v = kerneltable[b+KernelHalfWidth+x] / sum;
+      kerneltable[b+KernelHalfWidth+x]=v;
+      kerneltable[b+KernelHalfWidth-x]=v;
+    }
+  }
+}
diff --git a/package_bgs/ae/KernelTable.h b/package_bgs/ae/KernelTable.h
new file mode 100644
index 0000000000000000000000000000000000000000..bc37cc4f0a8befb16cf987f7c0f7e697400b1dff
--- /dev/null
+++ b/package_bgs/ae/KernelTable.h
@@ -0,0 +1,71 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*
+* Copyright 2001 by Ahmed Elgammal All  rights reserved.
+*
+* Permission to use, copy,  or modify this software and  its documentation
+* for  educational  and  research purposes only and without fee  is hereby
+* granted, provided  that this copyright notice and the original authors's
+* name appear  on all copies and supporting documentation.  If individual
+* files are  separated from  this  distribution directory  structure, this
+* copyright notice must be included.  For any other uses of this software,
+* in original or  modified form, including but not limited to distribution
+* in whole or in  part, specific  prior permission  must be  obtained from
+* Author or UMIACS.  These programs shall not  be  used, rewritten, or  
+* adapted as  the basis  of  a commercial  software  or  hardware product 
+* without first obtaining appropriate licenses  from Author. 
+* Other than these cases, no part of this software may be used or
+* distributed without written permission of the author.
+*
+* Neither the author nor UMIACS make any representations about the 
+* suitability of this software for any purpose.  It is provided 
+* "as is" without express or implied warranty.
+*
+* Ahmed Elgammal
+* 
+* University of Maryland at College Park
+* UMIACS
+* A.V. Williams Bldg. 
+* CollegePark, MD 20742
+* E-mail:  elgammal@umiacs.umd.edu
+*
+**/
+
+#ifndef __KERNEL_TABLE__
+#define __KERNEL_TABLE__
+
+#include <iostream>
+
+class KernelLUTable
+{
+public:
+  double minsegma;
+  double maxsegma;
+  int segmabins;
+  int tablehalfwidth;
+  double *kerneltable;
+  double *kernelsums;
+
+public:
+  KernelLUTable();
+  ~KernelLUTable();
+
+  KernelLUTable(int KernelHalfWidth,double Segmamin,double Segmamax,int Segmabins);
+};
+
+#endif
diff --git a/package_bgs/ae/NPBGSubtractor.cpp b/package_bgs/ae/NPBGSubtractor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f77a9a225b8ae6a1ae54f716e29575aea5dd50d
--- /dev/null
+++ b/package_bgs/ae/NPBGSubtractor.cpp
@@ -0,0 +1,1160 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*
+* Copyright 2001 by Ahmed Elgammal All  rights reserved.
+*
+* Permission to use, copy,  or modify this software and  its documentation
+* for  educational  and  research purposes only and without fee  is hereby
+* granted, provided  that this copyright notice and the original authors's
+* name appear  on all copies and supporting documentation.  If individual
+* files are  separated from  this  distribution directory  structure, this
+* copyright notice must be included.  For any other uses of this software,
+* in original or  modified form, including but not limited to distribution
+* in whole or in  part, specific  prior permission  must be  obtained from
+* Author or UMIACS.  These programs shall not  be  used, rewritten, or  
+* adapted as  the basis  of  a commercial  software  or  hardware product 
+* without first obtaining appropriate licenses  from Author. 
+* Other than these cases, no part of this software may be used or
+* distributed without written permission of the author.
+*
+* Neither the author nor UMIACS make any representations about the 
+* suitability of this software for any purpose.  It is provided 
+* "as is" without express or implied warranty.
+*
+* Ahmed Elgammal
+* 
+* University of Maryland at College Park
+* UMIACS
+* A.V. Williams Bldg. 
+* CollegePark, MD 20742
+* E-mail:  elgammal@umiacs.umd.edu
+*
+**/
+
+// NPBGSubtractor.cpp: implementation of the NPBGSubtractor class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "NPBGSubtractor.h"
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+//#ifdef _DEBUG
+//#undef THIS_FILE
+//static char THIS_FILE[]=__FILE__;
+//#define new DEBUG_NEW
+//#endif
+
+void BGR2SnGnRn(unsigned char * in_image,
+                unsigned char * out_image,
+                unsigned int rows,
+                unsigned int cols)
+{
+  unsigned int i;
+  unsigned int r1,r2,r3;
+  unsigned int r,g,b;
+  double s;
+
+  for(i = 0; i < rows*cols*3; i += 3)
+  {
+    b=in_image[i];
+    g=in_image[i+1];
+    r=in_image[i+2];
+
+    // calculate color ratios
+    s = (double) 255 / (double) (b+g+r+30);
+
+    r2 =(unsigned int) ((g+10) * s );
+    r3 =(unsigned int) ((r+10) * s );
+
+    out_image[i]   = (unsigned char) (((unsigned int) b+g+r) / 3);
+    out_image[i+1] = (unsigned char) (r2 > 255 ? 255 : r2) ;
+    out_image[i+2] = (unsigned char) (r3 > 255 ? 255 : r3) ;
+  }
+}
+
+void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist)
+{
+  unsigned int j;
+  int bin,diff;
+
+  unsigned int  imagesize	= pHist->imagesize;
+  unsigned char histbins	= pHist->histbins;
+  unsigned char *pAbsDiffHist = pHist->Hist;
+
+  int histbins_1 = histbins-1;
+  
+  for(j = 0; j < imagesize; j++)
+  {
+    diff = (int) image1[j] - (int) image2[j];
+    diff = abs(diff);
+    // update histogram
+    bin = (diff < histbins ? diff : histbins_1);
+    pAbsDiffHist[j*histbins+bin]++;
+  }
+}
+
+void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist)
+{
+  unsigned char * Hist		   = pAbsDiffHist->Hist;
+  unsigned char * MedianBins = pAbsDiffHist->MedianBins;
+  unsigned char * AccSum	   = pAbsDiffHist->AccSum;
+  unsigned char histsum		   = pAbsDiffHist->histsum;
+  unsigned char histbins		 = pAbsDiffHist->histbins;
+  unsigned int imagesize		 = pAbsDiffHist->imagesize;
+
+  int sum;
+  int bin;
+  unsigned int histindex;
+  unsigned char medianCount=histsum/2;
+  unsigned int j;
+
+  // find medians
+  for(j = 0; j < imagesize; j++)
+  {
+    // find the median
+    bin=0;
+    sum=0;
+
+    histindex=j*histbins;
+
+    while(sum < medianCount)
+    {
+      sum+=Hist[histindex+bin];
+      bin++;
+    }
+
+    bin--;
+
+    MedianBins[j]=bin;
+    AccSum[j]=sum;
+  }
+}
+
+DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence,
+  unsigned int rows,
+  unsigned int cols,
+  unsigned int color_channels,
+  unsigned int SequenceLength,
+  unsigned int histbins)
+{
+
+  unsigned int imagesize=rows*cols*color_channels;
+  unsigned int i;
+
+  DynamicMedianHistogram Hist;
+
+  unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins];
+  unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels];
+  unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels];
+  unsigned char *pAccSum = new unsigned char[rows*cols*color_channels];
+
+  memset(pAbsDiffHist,0,rows*cols*color_channels*histbins);
+
+  Hist.Hist = pAbsDiffHist;
+  Hist.MedianBins = pMedianBins;
+  Hist.MedianFreq = pMedianFreq;
+  Hist.AccSum = pAccSum;
+  Hist.histbins = histbins;
+  Hist.imagesize = rows*cols*color_channels;
+  Hist.histsum = SequenceLength-1;
+
+  unsigned char *image1, *image2;
+  for(i = 1; i < SequenceLength; i++)
+  {
+    // find diff between frame i,i-1;
+    image1 = pSequence+(i-1)*imagesize;
+    image2 = pSequence+(i)*imagesize;
+
+    UpdateDiffHist(image1,image2,&Hist);
+  }
+
+  FindHistMedians(&Hist);
+
+  return Hist;
+}
+
+void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist,
+                                unsigned char * pSDs,
+                                unsigned int imagesize,
+                                double MinSD,
+                                double MaxSD,
+                                unsigned int kernelbins)
+{
+  double v;
+  double kernelbinfactor=(kernelbins-1)/(MaxSD-MinSD);
+  int medianCount; 
+  int sum;
+  int bin;
+  unsigned int histindex;
+  unsigned int j;
+  unsigned int x1,x2;
+
+  unsigned char *Hist		    =pAbsDiffHist->Hist;
+  unsigned char *MedianBins	=pAbsDiffHist->MedianBins;
+  unsigned char *AccSum		  =pAbsDiffHist->AccSum;
+  unsigned char histsum		  =pAbsDiffHist->histsum;
+  unsigned char histbins		=pAbsDiffHist->histbins;
+
+  medianCount=(histsum)/2 ;
+
+  for(j = 0; j < imagesize; j++)
+  {
+    histindex=j*histbins;
+
+    bin=MedianBins[j];
+    sum=AccSum[j];
+
+    x1=sum-Hist[histindex+bin];
+    x2=sum;
+
+    // interpolate to get the median
+    // x1 < 50 % < x2
+
+    v =1.04 * ((double) bin-(double) (x2-medianCount)/ (double) (x2-x1));
+    v=( v <= MinSD ? MinSD : v);
+
+    // convert sd to kernel table bin
+
+    bin=(int) (v>=MaxSD ? kernelbins-1 : floor((v-MinSD)*kernelbinfactor+.5));
+
+    assert(bin>=0 && bin < kernelbins );
+
+    pSDs[j]=bin;
+  }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+NPBGSubtractor::NPBGSubtractor(){}
+
+NPBGSubtractor::~NPBGSubtractor()
+{
+  delete AbsDiffHist.Hist;
+  delete AbsDiffHist.MedianBins;
+  delete AbsDiffHist.MedianFreq;
+  delete AbsDiffHist.AccSum;
+  delete KernelTable;
+  delete BGModel->SDbinsImage;
+  delete BGModel;
+  delete Pimage1;
+  delete Pimage2;
+  delete tempFrame;
+  delete imageindex->List;
+  delete imageindex;
+}
+
+int NPBGSubtractor::Intialize(unsigned int prows,
+                              unsigned int pcols,
+                              unsigned int pcolor_channels,
+                              unsigned int SequenceLength,
+                              unsigned int pTimeWindowSize,
+                              unsigned char pSDEstimationFlag,
+                              unsigned char pUseColorRatiosFlag)
+{
+
+  rows=prows;
+  cols=pcols;
+  color_channels=pcolor_channels;
+  imagesize=rows*cols*color_channels;
+  SdEstimateFlag = pSDEstimationFlag;
+  UseColorRatiosFlag=pUseColorRatiosFlag;
+  //SampleSize = SequenceLength;
+
+  AdaptBGFlag = FALSE;
+  //
+  SubsetFlag = TRUE;
+
+  UpdateSDRate = 0;
+
+  BGModel = new NPBGmodel(rows,cols,color_channels,SequenceLength,pTimeWindowSize,500);
+
+  Pimage1= new double[rows*cols];
+  Pimage2= new double[rows*cols];
+
+  tempFrame= new unsigned char[rows*cols*3];
+
+  imageindex = new ImageIndex;
+  imageindex->List= new unsigned int [rows*cols];
+
+  // error checking
+  if (BGModel==NULL)
+    return 0;
+
+  return 1;
+}
+
+void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer)
+{
+  if(UseColorRatiosFlag && color_channels==3)
+    BGR2SnGnRn(ImageBuffer,ImageBuffer,rows,cols);
+  
+  BGModel->AddFrame(ImageBuffer);
+}
+
+void NPBGSubtractor::Estimation()
+{
+  int SampleSize=BGModel->SampleSize;
+
+  memset(BGModel->TemporalMask,0,rows*cols*BGModel->TemporalBufferLength);
+
+  //BGModel->AccMask= new unsigned int [rows*cols];
+  memset(BGModel->AccMask,0,rows*cols*sizeof(unsigned int));
+
+  unsigned char *pSDs = new unsigned char[rows*cols*color_channels];
+
+  //DynamicMedianHistogram AbsDiffHist;
+
+  int Abshistbins = 20;
+
+  TimeIndex=0;
+
+  // estimate standard deviations 
+
+  if(SdEstimateFlag)
+  {
+    AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence,rows,cols,color_channels,SampleSize,Abshistbins);
+    EstimateSDsFromAbsDiffHist(&AbsDiffHist,pSDs,imagesize,SEGMAMIN,SEGMAMAX,SEGMABINS);
+  }
+  else
+  {
+    unsigned int bin;
+    bin = (unsigned int) floor(((DEFAULTSEGMA-SEGMAMIN)*SEGMABINS)/(SEGMAMAX-SEGMAMIN));
+    memset(pSDs,bin,rows*cols*color_channels*sizeof(unsigned char));
+  }
+
+  BGModel->SDbinsImage=pSDs;
+
+  // Generate the Kernel
+  KernelTable = new KernelLUTable(KERNELHALFWIDTH,SEGMAMIN,SEGMAMAX,SEGMABINS);
+}
+
+/*********************************************************************/
+
+void BuildImageIndex(unsigned char * Image,
+                     ImageIndex * imageIndex,
+                     unsigned int rows,
+                     unsigned int cols)
+{
+  unsigned int i,j;
+  unsigned int r,c;
+  unsigned int * image_list;
+
+  j=cols+1;
+  i=0;
+  image_list=imageIndex->List;
+
+  for(r = 1; r < rows-1; r++)
+  {
+    for(c = 1; c < cols-1; c++)
+    {
+      if(Image[j])
+        image_list[i++]=j;
+      
+      j++;
+    }
+    j+=2;
+  }
+
+  imageIndex->cnt = i;
+}
+
+/*********************************************************************/
+
+void HystExpandOperatorIndexed(unsigned char * inImage,
+                               ImageIndex * inIndex,
+                               double * Pimage,
+                               double hyst_th,
+                               unsigned char * outImage,
+                               ImageIndex * outIndex,
+                               unsigned int urows,
+                               unsigned int ucols)
+{
+  unsigned int * in_list;
+  unsigned int in_cnt;
+  unsigned int * out_list;
+
+  int rows,cols;
+
+  int Nbr[9];
+  unsigned int i,j;
+  unsigned int k;
+  unsigned int idx;
+
+  rows=(int)  urows;
+  cols=(int)  ucols;
+
+  in_cnt=inIndex->cnt;
+  in_list=inIndex->List;
+
+  Nbr[0]=-cols-1;
+  Nbr[1]=-cols;
+  Nbr[2]=-cols+1;
+  Nbr[3]=-1;
+  Nbr[4]=0;
+  Nbr[5]=1;
+  Nbr[6]=cols-1;
+  Nbr[7]=cols;
+  Nbr[8]=cols+1;
+
+  memset(outImage,0,rows*cols);
+
+  out_list=outIndex->List;
+  k=0;
+  
+  for(i = 0; i < in_cnt; i++)
+  {
+    for(j = 0; j < 9; j++)
+    {
+      idx = in_list[i] + Nbr[j];
+
+      if(Pimage[idx] < hyst_th)
+        outImage[idx] = 255;
+    }
+  }
+
+  // build index for out image
+  BuildImageIndex(outImage,outIndex,urows,ucols);
+}
+
+/*********************************************************************/
+
+void HystShrinkOperatorIndexed(unsigned char * inImage,
+                               ImageIndex * inIndex,
+                               double * Pimage,
+                               double hyst_th,
+                               unsigned char * outImage,
+                               ImageIndex * outIndex,
+                               unsigned int urows,
+                               unsigned int ucols)
+{
+  unsigned int * in_list;
+  unsigned int in_cnt;
+  unsigned int * out_list;
+
+  int rows,cols;
+
+  int Nbr[9];
+  unsigned int i,j;
+  unsigned int k,idx;
+
+  rows=(int) urows;
+  cols=(int) ucols;
+
+  in_cnt=inIndex->cnt;
+  in_list=inIndex->List;
+
+  Nbr[0]=-cols-1;
+  Nbr[1]=-cols;
+  Nbr[2]=-cols+1;
+  Nbr[3]=-1;
+  Nbr[4]=0;
+  Nbr[5]=1;
+  Nbr[6]=cols-1;
+  Nbr[7]=cols;
+  Nbr[8]=cols+1;
+
+  memset(outImage,0,rows*cols);
+
+  out_list=outIndex->List;
+  k=0;
+  
+  for(i = 0; i < in_cnt; i++)
+  {
+    idx = in_list[i];
+    j = 0;
+
+    while(j < 9 && inImage[idx+Nbr[j]])
+      j++;
+    
+    if(j >= 9 || Pimage[idx] <= hyst_th)
+      outImage[idx]=255;
+  }
+
+  BuildImageIndex(outImage,outIndex,rows,cols);
+}
+
+/*********************************************************************/
+
+void ExpandOperatorIndexed(unsigned char * inImage,
+                           ImageIndex * inIndex,
+                           unsigned char * outImage,
+                           ImageIndex * outIndex,
+                           unsigned int urows,
+                           unsigned int ucols)
+{
+  unsigned int * in_list;
+  unsigned int in_cnt;
+  unsigned int * out_list;
+
+  int rows,cols;
+
+  int Nbr[9];
+  unsigned int i,j;
+  unsigned int k;
+  unsigned int idx;
+
+  rows=(int)  urows;
+  cols=(int)  ucols;
+
+  in_cnt=inIndex->cnt;
+  in_list=inIndex->List;
+
+  Nbr[0]=-cols-1;
+  Nbr[1]=-cols;
+  Nbr[2]=-cols+1;
+  Nbr[3]=-1;
+  Nbr[4]=0;
+  Nbr[5]=1;
+  Nbr[6]=cols-1;
+  Nbr[7]=cols;
+  Nbr[8]=cols+1;
+
+
+  memset(outImage,0,rows*cols);
+
+
+  out_list=outIndex->List;
+  k=0;
+  for (i=0; i<in_cnt;i++)
+    for (j=0;j<9;j++) {
+      idx=in_list[i]+Nbr[j];
+      outImage[idx]=255;
+    }
+
+
+    // build index for out image
+
+    BuildImageIndex(outImage,outIndex,rows,cols);
+
+}
+
+/*********************************************************************/
+
+void ShrinkOperatorIndexed(unsigned char * inImage,
+                           ImageIndex * inIndex,
+                           unsigned char * outImage,
+                           ImageIndex * outIndex,
+                           unsigned int urows,
+                           unsigned int ucols)
+{
+
+  unsigned int * in_list;
+  unsigned int in_cnt;
+  unsigned int * out_list;
+
+  int rows,cols;
+
+  int Nbr[9];
+  unsigned int i,j;
+  unsigned int k,idx;
+
+  rows=(int) urows;
+  cols=(int) ucols;
+
+  in_cnt=inIndex->cnt;
+  in_list=inIndex->List;
+
+  Nbr[0]=-cols-1;
+  Nbr[1]=-cols;
+  Nbr[2]=-cols+1;
+  Nbr[3]=-1;
+  Nbr[4]=0;
+  Nbr[5]=1;
+  Nbr[6]=cols-1;
+  Nbr[7]=cols;
+  Nbr[8]=cols+1;
+
+
+  memset(outImage,0,rows*cols);
+
+  out_list=outIndex->List;
+  k=0;
+  for (i=0; i<in_cnt;i++) {
+    idx=in_list[i];
+    j=0;
+
+    while ( j<9 && inImage[idx+Nbr[j]]){
+      j++;
+    }
+
+    if (j>=9) {
+      outImage[idx]=255;
+    }
+  }
+
+  BuildImageIndex(outImage,outIndex,rows,cols);
+}
+
+/*********************************************************************/
+
+void NoiseFilter_o(unsigned char * Image,
+                   unsigned char * ResultIm,
+                   int rows,
+                   int cols,
+                   unsigned char th)
+{
+  /* assuming input is 1 for on, 0 for off */
+
+
+  int r,c;
+  unsigned char *p,*n,*nw,*ne,*e,*w,*s,*sw,*se;
+  unsigned int v;
+  unsigned int TH;
+
+  unsigned char * ResultPtr;
+
+  TH=255*th;
+
+  memset(ResultIm,0,rows*cols);
+
+  p=Image+cols+1;
+  ResultPtr=ResultIm+cols+1;
+
+  for(r=1;r<rows-1;r++)
+  {
+    for(c=1;c<cols-1;c++)
+    {
+      if (*p)
+      {
+        n=p-cols;
+        ne=n+1;
+        nw=n-1;
+        e=p+1;
+        w=p-1;
+        s=p+cols;
+        se=s+1;
+        sw=s-1;
+
+        v=(unsigned int) *nw+*n+*ne+*w+*e+*sw+*s+*se;
+
+        if (v>=TH)
+          *ResultPtr=255;
+        else
+          *ResultPtr=0;
+      }
+      p++;
+      ResultPtr++;
+    }
+    p+=2;
+    ResultPtr+=2;
+  }
+}
+
+/*********************************************************************/
+
+void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image,
+                                            unsigned char * Mask)
+{
+  unsigned int i,ic;
+  unsigned char * pSequence 	=BGModel->Sequence;
+  unsigned char * PixelQTop		=BGModel->PixelQTop;
+  unsigned int Top						=BGModel->Top;
+  unsigned int rate;
+
+  int TemporalBufferTop						=(int) BGModel->TemporalBufferTop;
+  unsigned char * pTemporalBuffer	= BGModel->TemporalBuffer;
+  unsigned char * pTemporalMask		= BGModel->TemporalMask;
+  int TemporalBufferLength				= BGModel->TemporalBufferLength;
+
+  unsigned int * AccMask		=	BGModel->AccMask;
+  unsigned int ResetMaskTh	= BGModel->ResetMaskTh;
+
+  unsigned char *pAbsDiffHist = AbsDiffHist.Hist;
+  unsigned char histbins = AbsDiffHist.histbins;
+  int histbins_1=histbins-1;
+
+  int TimeWindowSize = BGModel->TimeWindowSize;
+  int SampleSize = BGModel->SampleSize;
+
+  int TemporalBufferNext;
+
+  unsigned int imagebuffersize=rows*cols*color_channels;
+  unsigned int imagespatialsize=rows*cols;
+
+  unsigned char mask;
+
+  unsigned int histindex;
+  unsigned char diff;
+  unsigned char bin;
+
+  static int TBCount=0;
+
+  unsigned char * pTBbase1, * pTBbase2;
+  unsigned char * pModelbase1, * pModelbase2;
+
+  rate=TimeWindowSize/SampleSize;
+  rate=(rate > 2) ? rate : 2;
+
+
+  TemporalBufferNext=(TemporalBufferTop+1) 
+    % TemporalBufferLength;
+
+  // pointers to Masks : Top and Next
+  unsigned char * pTMaskTop=pTemporalMask+TemporalBufferTop*imagespatialsize;
+  unsigned char * pTMaskNext=pTemporalMask+TemporalBufferNext*imagespatialsize;
+
+  // pointers to TB frames: Top and Next
+  unsigned char * pTBTop=pTemporalBuffer+TemporalBufferTop*imagebuffersize;
+  unsigned char * pTBNext=pTemporalBuffer+TemporalBufferNext*imagebuffersize;
+
+  if ( ((TimeIndex) % rate == 0)  && TBCount >= TemporalBufferLength )
+  {
+    for(i=0,ic=0;i<imagespatialsize;i++,ic+=color_channels)
+    {
+      mask= * (pTMaskTop+i) || * (pTMaskNext+i);
+
+      if(!mask)
+      {
+        // pointer to TB pixels to be added to the model
+        pTBbase1=pTBTop+ic;
+        pTBbase2=pTBNext+ic;
+
+        // pointers to Model pixels to be replaced
+        pModelbase1=pSequence+PixelQTop[i]*imagebuffersize+ic;
+        pModelbase2=pSequence+((PixelQTop[i]+1)% SampleSize)*imagebuffersize+ic;
+
+        // update Deviation Histogram
+        if(SdEstimateFlag)
+        {
+          if(color_channels==1)
+          {
+            histindex=i*histbins;	
+
+            // add new pair from temporal buffer
+            diff=(unsigned char) abs((int) *pTBbase1 - (int) *pTBbase2);
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]++;
+
+
+            // remove old pair from the model
+            diff=(unsigned char) abs((int) *pModelbase1-(int) *pModelbase2);
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]--;
+          }
+          else
+          {
+            // color
+
+            // add new pair from temporal buffer
+            histindex=ic*histbins;	
+            diff=abs(*pTBbase1 -
+              *pTBbase2);
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]++;
+
+            histindex+=histbins;	
+            diff=abs(*(pTBbase1+1) -
+              *(pTBbase2+1));
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]++;
+
+            histindex+=histbins;	
+            diff=abs(*(pTBbase1+2) -
+              *(pTBbase2+2));
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]++;
+
+            // remove old pair from the model
+            histindex=ic*histbins;	
+
+            diff=abs(*pModelbase1-
+              *pModelbase2);
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]--;
+
+            histindex+=histbins;	
+            diff=abs(*(pModelbase1+1)-
+              *(pModelbase2+1));
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]--;
+
+            histindex+=histbins;	
+            diff=abs(*(pModelbase1+2)-
+              *(pModelbase2+2));
+            bin=(diff < histbins ? diff : histbins_1);
+            pAbsDiffHist[histindex+bin]--;
+          }
+        }
+
+        // add new pair into the model
+        memcpy(pModelbase1,pTBbase1, color_channels*sizeof(unsigned char));
+
+        memcpy(pModelbase2,pTBbase2, color_channels*sizeof(unsigned char));
+
+        PixelQTop[i]=(PixelQTop[i]+2) % SampleSize;
+      }
+    }
+  } // end if (sampling event)
+
+  // update temporal buffer
+  // add new frame to Temporal buffer.
+  memcpy(pTBTop,image,imagebuffersize);
+
+  // update AccMask
+  // update new Mask with information in AccMask
+
+  for (i=0;i<rows*cols;i++)
+  {
+    if (Mask[i])
+      AccMask[i]++;
+    else
+      AccMask[i]=0;
+
+    if (AccMask[i] > ResetMaskTh)
+      Mask[i]=0;
+  }
+
+  // add new mask
+  memcpy(pTMaskTop,Mask,imagespatialsize);
+
+  // advance Temporal buffer pointer
+  TemporalBufferTop=(TemporalBufferTop+1) % TemporalBufferLength;
+
+  BGModel->TemporalBufferTop=TemporalBufferTop;
+
+  TBCount++;
+
+  // estimate SDs
+
+  if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0))
+  {
+    double MaxSD = KernelTable->maxsegma;
+    double MinSD = KernelTable->minsegma;
+    int KernelBins = KernelTable->segmabins;
+
+    unsigned char * pSDs= BGModel->SDbinsImage;
+
+    FindHistMedians(&(AbsDiffHist));
+    EstimateSDsFromAbsDiffHist(&(AbsDiffHist),pSDs,imagebuffersize,MinSD,MaxSD,KernelBins);
+  }
+
+  TimeIndex++;
+}
+
+/*********************************************************************/
+
+void DisplayPropabilityImageWithThresholding(double * Pimage,
+                                             unsigned char * DisplayImage,
+                                             double Threshold,
+                                             unsigned int rows,
+                                             unsigned int cols)
+{
+  double p;
+
+  for(unsigned int i=0;i<rows*cols;i++)
+  {
+    p = Pimage[i];
+
+    DisplayImage[i]=(p > Threshold) ?  0 : 255;
+  }
+}
+
+/*********************************************************************/
+
+void NPBGSubtractor::NPBGSubtraction_Subset_Kernel(
+  unsigned char * image,
+  unsigned char * FGImage,
+  unsigned char * FilteredFGImage)
+{
+  unsigned int i,j;
+  unsigned char *pSequence 	=BGModel->Sequence;
+
+  unsigned int SampleSize			= BGModel->SampleSize;
+
+  double *kerneltable	= KernelTable->kerneltable;
+  int KernelHalfWidth		= KernelTable->tablehalfwidth;
+  double *KernelSum			= KernelTable->kernelsums;
+  double KernelMaxSigma = KernelTable->maxsegma;
+  double KernelMinSigma = KernelTable->minsegma;
+  int KernelBins				= KernelTable->segmabins;
+  unsigned char * SDbins= BGModel->SDbinsImage;
+
+  unsigned char * SaturationImage=FilteredFGImage;
+
+  // default sigmas .. to be removed.
+  double sigma1;
+  double sigma2;
+  double sigma3;
+
+  sigma1=2.25;
+  sigma2=2.25;
+  sigma3=2.25;
+
+  double p;
+  double th;
+
+  double alpha,beta,beta_over_alpha, betau,betau_over_alpha;
+
+  alpha= AlphaValue;
+
+  /* intialize FG image */
+
+  memset(FGImage,0,rows*cols);
+
+  //Threshold=1;
+  th = Threshold * SampleSize;
+
+  double sum=0,kernel1,kernel2,kernel3;
+  int k,g;
+
+
+  if (color_channels==1) 
+  {
+    // gray scale
+
+    int kernelbase;
+    
+    for (i=0;i<rows*cols;i++)
+    {
+      kernelbase=SDbins[i]*(2*KernelHalfWidth+1);
+      sum=0;
+      j=0;
+
+      while (j<SampleSize && sum < th)
+      {
+        g=pSequence[j*imagesize+i];
+        k= g-  image[i] +KernelHalfWidth;
+        sum+=kerneltable[kernelbase+k];
+        j++;
+      }
+
+      p=sum/j;
+      Pimage1[i]=p;
+    }
+  }
+  else if (UseColorRatiosFlag && SubsetFlag)
+  {
+    // color ratios
+
+    unsigned int ig;
+    int base;
+
+    int kernelbase1;
+    int kernelbase2;
+    int kernelbase3;
+
+    unsigned int kerneltablewidth=2*KernelHalfWidth+1;
+
+    beta=3.0;    // minimum bound on the range.
+    betau=100.0;
+
+    beta_over_alpha = beta / alpha;
+    betau_over_alpha = betau / alpha;
+
+
+    double brightness_lowerbound = 1-alpha;
+    double brightness_upperbound = 1+alpha;
+    int x1,x2;
+    unsigned int SubsampleCount;
+
+    for (i=0,ig=0;i<imagesize;i+=3,ig++)
+    {
+      kernelbase1=SDbins[i]*kerneltablewidth;
+      kernelbase2=SDbins[i+1]*kerneltablewidth;
+      kernelbase3=SDbins[i+2]*kerneltablewidth;
+
+      sum=0;
+      j=0;
+      SubsampleCount=0;
+
+      while (j<SampleSize && sum < th)
+      {
+        base=j*imagesize+i;
+        g=pSequence[base];
+        
+        if (g < beta_over_alpha)
+        {
+          x1=(int) (g-beta);
+          x2=(int) (g+beta);
+        }
+        else if (g > betau_over_alpha)
+        {
+          x1=(int) (g-betau);
+          x2=(int) (g+betau);
+        }
+        else
+        {
+          x1=(int) (g*brightness_lowerbound+0.5);
+          x2=(int) (g*brightness_upperbound+0.5);
+        }
+
+        if(x1<image[i] && image[i] <x2)
+        {
+          g=pSequence[base+1];
+          k= (g-  image[i+1]) +KernelHalfWidth;
+          kernel2=kerneltable[kernelbase2+k];
+
+          g=pSequence[base+2];
+          k= (g-  image[i+2]) +KernelHalfWidth;
+          kernel3=kerneltable[kernelbase3+k];
+
+          sum+=kernel2*kernel3;
+
+          SubsampleCount++;
+        }
+        j++;
+      }
+
+      p=sum / j;
+      Pimage1[ig]=p;
+    }	
+  }
+  else if (UseColorRatiosFlag && ! SubsetFlag)
+  {
+    // color ratios
+
+    unsigned int ig;
+    int base;
+    int bin;
+
+    int kernelbase1;
+    int kernelbase2;
+    int kernelbase3;
+
+    unsigned int kerneltablewidth=2*KernelHalfWidth+1;
+
+    int gmin,gmax;
+    double gfactor;
+
+    gmax=200;
+    gmin=10;
+
+    gfactor = (KernelMaxSigma-KernelMinSigma) / (double) (gmax - gmin);
+
+    for (i=0,ig=0;i<imagesize;i+=3,ig++)
+    {
+
+      bin=(int) floor(((alpha*16-KernelMinSigma)*KernelBins)/(KernelMaxSigma-KernelMinSigma));
+
+      kernelbase1=bin*kerneltablewidth;
+      kernelbase2=SDbins[i+1]*kerneltablewidth;
+      kernelbase3=SDbins[i+2]*kerneltablewidth;
+
+      sum=0;
+      j=0;
+
+      while (j<SampleSize && sum < th)
+      {
+        base=j*imagesize+i;
+        g=pSequence[base];
+
+        if (g < gmin )
+          bin=0;
+        else if (g > gmax)
+          bin = KernelBins -1 ;
+        else
+          bin= (int) ((g-gmin) * gfactor + 0.5);
+        
+        kernelbase1=bin*kerneltablewidth;
+
+        k= (g-  image[i]) +KernelHalfWidth;
+        kernel1=kerneltable[kernelbase1+k];
+
+        g=pSequence[base+1];
+        k= (g-  image[i+1]) +KernelHalfWidth;
+        kernel2=kerneltable[kernelbase2+k];
+
+        g=pSequence[base+2];
+        k= (g-  image[i+2]) +KernelHalfWidth;
+        kernel3=kerneltable[kernelbase3+k];
+
+        sum+=kernel1*kernel2*kernel3;
+        j++;
+      }
+
+      p=sum / j;
+      Pimage1[ig]=p;
+    }
+  }
+  else // RGB color
+  {
+    unsigned int ig;
+    int base;
+
+    int kernelbase1;
+    int kernelbase2;
+    int kernelbase3;
+    unsigned int kerneltablewidth=2*KernelHalfWidth+1;
+
+    for (i=0,ig=0;i<imagesize;i+=3,ig++)
+    {
+      // used extimated kernel width to access the right kernel
+      kernelbase1=SDbins[i]*kerneltablewidth;
+      kernelbase2=SDbins[i+1]*kerneltablewidth;
+      kernelbase3=SDbins[i+2]*kerneltablewidth;
+
+      sum=0;
+      j=0;
+      while (j<SampleSize && sum < th)
+      {
+        base=j*imagesize+i;
+        g=pSequence[base];
+        k= (g-  image[i]) +KernelHalfWidth;
+        kernel1=kerneltable[kernelbase1+k];
+
+        g=pSequence[base+1];
+        k= (g-  image[i+1]) +KernelHalfWidth;
+        kernel2=kerneltable[kernelbase2+k];
+
+        g=pSequence[base+2];
+        k= (g-  image[i+2]) +KernelHalfWidth;
+        kernel3=kerneltable[kernelbase3+k];
+
+        sum+=kernel1*kernel2*kernel3;
+        j++;
+      }
+      
+      p=sum/j;
+      Pimage1[ig]=p;
+    }
+  }
+
+  DisplayPropabilityImageWithThresholding(Pimage1,FGImage,Threshold,rows,cols);
+}
+
+/*********************************************************************/
+
+void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame,
+                                     unsigned char * FGImage,
+                                     unsigned char * FilteredFGImage,
+                                     unsigned char ** DisplayBuffers)
+{
+  if(UseColorRatiosFlag)
+    BGR2SnGnRn(Frame,tempFrame,rows,cols);
+  else
+    memcpy(tempFrame,Frame,rows*cols*color_channels);
+
+  NPBGSubtraction_Subset_Kernel(tempFrame,FGImage,FilteredFGImage);	
+  /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4);
+  BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols);
+
+  ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols);
+  ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols);
+
+  memset(DisplayBuffers[3],0,rows*cols);*/
+}
+
+void NPBGSubtractor::Update(unsigned char * FGMask)
+{
+  if(UpdateBGFlag)
+    SequenceBGUpdate_Pairs(tempFrame,FGMask);
+}
diff --git a/package_bgs/ae/NPBGSubtractor.h b/package_bgs/ae/NPBGSubtractor.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7f379542767bec2b6e47b1b1b74a2574e58ebb9
--- /dev/null
+++ b/package_bgs/ae/NPBGSubtractor.h
@@ -0,0 +1,154 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*
+* Copyright 2001 by Ahmed Elgammal All  rights reserved.
+*
+* Permission to use, copy,  or modify this software and  its documentation
+* for  educational  and  research purposes only and without fee  is hereby
+* granted, provided  that this copyright notice and the original authors's
+* name appear  on all copies and supporting documentation.  If individual
+* files are  separated from  this  distribution directory  structure, this
+* copyright notice must be included.  For any other uses of this software,
+* in original or  modified form, including but not limited to distribution
+* in whole or in  part, specific  prior permission  must be  obtained from
+* Author or UMIACS.  These programs shall not  be  used, rewritten, or  
+* adapted as  the basis  of  a commercial  software  or  hardware product 
+* without first obtaining appropriate licenses  from Author. 
+* Other than these cases, no part of this software may be used or
+* distributed without written permission of the author.
+*
+* Neither the author nor UMIACS make any representations about the 
+* suitability of this software for any purpose.  It is provided 
+* "as is" without express or implied warranty.
+*
+* Ahmed Elgammal
+* 
+* University of Maryland at College Park
+* UMIACS
+* A.V. Williams Bldg. 
+* CollegePark, MD 20742
+* E-mail:  elgammal@umiacs.umd.edu
+*
+**/
+
+// NPBGSubtractor.h: interface for the NPBGSubtractor class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_NPBGSUBTRACTOR_H__84B0F51E_6E65_41E4_AC01_723B406363C4__INCLUDED_)
+#define AFX_NPBGSUBTRACTOR_H__84B0F51E_6E65_41E4_AC01_723B406363C4__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "NPBGmodel.h"
+#include "KernelTable.h"
+
+#define FALSE 0
+#define TRUE 1
+
+// kernal look up table settings
+#define 	KERNELHALFWIDTH 255
+#define 	SEGMAMAX 36.5
+#define	  SEGMAMIN 0.5
+#define		SEGMABINS 80
+#define		DEFAULTSEGMA 1.0
+
+typedef struct
+{
+  unsigned char *Hist;
+  unsigned char *MedianBins;
+  unsigned char *MedianFreq;
+  unsigned char *AccSum;
+  unsigned char histbins;
+  unsigned char histsum;
+  unsigned int  imagesize;
+} DynamicMedianHistogram;
+
+typedef struct
+{
+  unsigned int cnt;
+  unsigned int *List;
+} ImageIndex;
+
+class NPBGSubtractor  
+{
+private:
+  unsigned int rows;
+  unsigned int cols;
+  unsigned int color_channels;
+  unsigned int imagesize;
+  // flags
+  unsigned char UpdateBGFlag;
+  unsigned char SdEstimateFlag;
+  unsigned char UseColorRatiosFlag;
+  unsigned char AdaptBGFlag;
+  unsigned char SubsetFlag;
+  //
+  int UpdateSDRate;
+  double Threshold;
+  double AlphaValue;
+  unsigned int TimeIndex;
+  ImageIndex  *imageindex;
+  unsigned char *tempFrame;
+  KernelLUTable *KernelTable;
+  NPBGmodel *BGModel;
+  DynamicMedianHistogram AbsDiffHist;
+  double *Pimage1;
+  double *Pimage2;
+  //
+  void NPBGSubtraction_Subset_Kernel(unsigned char * image, unsigned char * FGImage, unsigned char * FilteredFGImage);
+  void SequenceBGUpdate_Pairs(unsigned char * image, unsigned char * Mask);
+
+public:
+  NPBGSubtractor();
+  virtual ~NPBGSubtractor();
+  //~NPBGSubtractor();
+
+  int Intialize(unsigned int rows,
+    unsigned int cols,
+    unsigned int color_channels,
+    unsigned int SequenceLength,
+    unsigned int TimeWindowSize,
+    unsigned char SDEstimationFlag,
+    unsigned char UseColorRatiosFlag);
+
+  void AddFrame(unsigned char * ImageBuffer);
+
+  void Estimation();
+
+  void NBBGSubtraction(unsigned char *Frame,
+    unsigned char *FGImage,
+    unsigned char *FilteredFGImage,
+    unsigned char **DisplayBuffers);
+
+  void Update(unsigned char *);
+
+  void SetThresholds(double th, double alpha)
+  {
+    Threshold = th;
+    AlphaValue = alpha;
+  };
+
+  void SetUpdateFlag(unsigned int bgflag){
+    UpdateBGFlag = bgflag;
+  };
+};
+
+#endif // !defined(AFX_NPBGSUBTRACTOR_H__84B0F51E_6E65_41E4_AC01_723B406363C4__INCLUDED_)
diff --git a/package_bgs/ae/NPBGmodel.cpp b/package_bgs/ae/NPBGmodel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2c8b07400992bf4db7810723b6fef930ed806ee3
--- /dev/null
+++ b/package_bgs/ae/NPBGmodel.cpp
@@ -0,0 +1,127 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*
+* Copyright 2001 by Ahmed Elgammal All  rights reserved.
+*
+* Permission to use, copy,  or modify this software and  its documentation
+* for  educational  and  research purposes only and without fee  is hereby
+* granted, provided  that this copyright notice and the original authors's
+* name appear  on all copies and supporting documentation.  If individual
+* files are  separated from  this  distribution directory  structure, this
+* copyright notice must be included.  For any other uses of this software,
+* in original or  modified form, including but not limited to distribution
+* in whole or in  part, specific  prior permission  must be  obtained from
+* Author or UMIACS.  These programs shall not  be  used, rewritten, or  
+* adapted as  the basis  of  a commercial  software  or  hardware product 
+* without first obtaining appropriate licenses  from Author. 
+* Other than these cases, no part of this software may be used or
+* distributed without written permission of the author.
+*
+* Neither the author nor UMIACS make any representations about the 
+* suitability of this software for any purpose.  It is provided 
+* "as is" without express or implied warranty.
+*
+* Ahmed Elgammal
+* 
+* University of Maryland at College Park
+* UMIACS
+* A.V. Williams Bldg. 
+* CollegePark, MD 20742
+* E-mail:  elgammal@umiacs.umd.edu
+*
+**/
+
+// NPBGmodel.cpp: implementation of the NPBGmodel class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "NPBGmodel.h"
+#include "memory.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+//#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+NPBGmodel::NPBGmodel()
+{
+  std::cout << "NPBGmodel()" << std::endl;
+}
+
+NPBGmodel::~NPBGmodel()
+{
+  delete Sequence;
+  delete PixelQTop;
+  delete TemporalBuffer;
+  delete TemporalMask;
+  delete AccMask;
+  //delete SDbinsImage;
+  std::cout << "~NPBGmodel()" << std::endl;
+}
+
+NPBGmodel::NPBGmodel(unsigned int Rows,
+                     unsigned int Cols,
+                     unsigned int ColorChannels,
+                     unsigned int Length,
+                     unsigned int pTimeWindowSize,
+                     unsigned int bg_suppression_time)
+{
+  std::cout << "NPBGmodel()" << std::endl;
+
+  imagesize = Rows*Cols*ColorChannels;
+
+  rows = Rows;
+  cols = Cols;
+  color_channels = ColorChannels;
+
+  SampleSize = Length;
+
+  TimeWindowSize = pTimeWindowSize;
+
+  Sequence	= new unsigned char[imagesize*Length];
+  Top = 0;
+  memset(Sequence,0,imagesize*Length);
+
+  PixelQTop = new unsigned char[rows*cols];
+
+  // temporalBuffer
+  TemporalBufferLength = (TimeWindowSize/Length > 2 ? TimeWindowSize/Length:2);
+  TemporalBuffer = new unsigned char[imagesize*TemporalBufferLength];
+  TemporalMask = new unsigned char[rows*cols*TemporalBufferLength];
+
+  TemporalBufferTop = 0;
+
+  AccMask = new unsigned int[rows*cols];
+
+  ResetMaskTh = bg_suppression_time;
+}
+
+void NPBGmodel::AddFrame(unsigned char *ImageBuffer)		
+{
+  memcpy(Sequence+Top*imagesize,ImageBuffer,imagesize);
+  Top = (Top + 1) % SampleSize;		
+
+  memset(PixelQTop, (unsigned char) Top, rows*cols);
+
+  memcpy(TemporalBuffer,ImageBuffer,imagesize);
+}
diff --git a/package_bgs/ae/NPBGmodel.h b/package_bgs/ae/NPBGmodel.h
new file mode 100644
index 0000000000000000000000000000000000000000..9e285108eec393167c327970aa1c783733c71447
--- /dev/null
+++ b/package_bgs/ae/NPBGmodel.h
@@ -0,0 +1,111 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*
+* Copyright 2001 by Ahmed Elgammal All  rights reserved.
+*
+* Permission to use, copy,  or modify this software and  its documentation
+* for  educational  and  research purposes only and without fee  is hereby
+* granted, provided  that this copyright notice and the original authors's
+* name appear  on all copies and supporting documentation.  If individual
+* files are  separated from  this  distribution directory  structure, this
+* copyright notice must be included.  For any other uses of this software,
+* in original or  modified form, including but not limited to distribution
+* in whole or in  part, specific  prior permission  must be  obtained from
+* Author or UMIACS.  These programs shall not  be  used, rewritten, or  
+* adapted as  the basis  of  a commercial  software  or  hardware product 
+* without first obtaining appropriate licenses  from Author. 
+* Other than these cases, no part of this software may be used or
+* distributed without written permission of the author.
+*
+* Neither the author nor UMIACS make any representations about the 
+* suitability of this software for any purpose.  It is provided 
+* "as is" without express or implied warranty.
+*
+* Ahmed Elgammal
+* 
+* University of Maryland at College Park
+* UMIACS
+* A.V. Williams Bldg. 
+* CollegePark, MD 20742
+* E-mail:  elgammal@umiacs.umd.edu
+*
+**/
+
+// NPBGmodel.h: interface for the NPBGmodel class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_NPBGMODEL_H__CCAF05D4_D06E_44C2_95D8_979E2249953A__INCLUDED_)
+#define AFX_NPBGMODEL_H__CCAF05D4_D06E_44C2_95D8_979E2249953A__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include <iostream>
+
+class NPBGmodel  
+{
+private:
+  unsigned char *Sequence;
+  unsigned int SampleSize;
+  unsigned int TimeWindowSize;
+
+  unsigned int rows,cols,color_channels;
+  unsigned int imagesize;
+
+  unsigned int Top;
+  unsigned char *PixelQTop;
+
+  //unsigned int *PixelUpdateCounter;
+
+  unsigned char *SDbinsImage; 
+
+  unsigned char *TemporalBuffer;
+  unsigned char TemporalBufferLength;
+  unsigned char TemporalBufferTop;
+  unsigned char *TemporalBufferMask;
+
+  unsigned char *TemporalMask;
+  unsigned char TemporalMaskLength;
+  unsigned char TemporalMaskTop;
+
+  unsigned int *AccMask;
+  unsigned int ResetMaskTh;	// Max continous duration a pixel can be detected before
+  // it is forced to be updated...
+
+  double *weights;
+
+public:
+  NPBGmodel();
+  //~NPBGmodel();
+  virtual ~NPBGmodel();
+
+  NPBGmodel(unsigned int Rows,
+    unsigned int Cols,
+    unsigned int ColorChannels,
+    unsigned int Length,
+    unsigned int pTimeWindowSize,
+    unsigned int bg_suppression_time);
+
+  void AddFrame(unsigned char *ImageBuffer);
+
+  friend class NPBGSubtractor;
+};
+
+#endif // !defined(AFX_NPBGMODEL_H__CCAF05D4_D06E_44C2_95D8_979E2249953A__INCLUDED_)
diff --git a/package_bgs/av/TBackground.cpp b/package_bgs/av/TBackground.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2e97d93804b29507cb7eb8b4c95276c7a0497e34
--- /dev/null
+++ b/package_bgs/av/TBackground.cpp
@@ -0,0 +1,166 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*  TBackground.cpp
+*  Framework
+*
+*  Created by Robinault Lionel on 07/12/11.
+*
+*/
+
+#include "TBackground.h"
+
+TBackground::TBackground(void)
+{
+  std::cout << "TBackground()" << std::endl;
+}
+
+TBackground::~TBackground(void)
+{
+  Clear();
+  std::cout << "~TBackground()" << std::endl;
+}
+
+void TBackground::Clear(void)
+{
+}
+
+void TBackground::Reset(void)
+{
+}
+
+int TBackground::GetParameterCount(void)
+{
+  return 0;
+}
+
+std::string TBackground::GetParameterName(int nInd)
+{
+  return "";
+}
+
+std::string TBackground::GetParameterValue(int nInd)
+{
+  return "";
+}
+
+int TBackground::SetParameterValue(int nInd, std::string csNew)
+{
+  return 0;
+}
+
+int TBackground::Init(IplImage * pSource)
+{
+  return 0;
+}
+
+bool TBackground::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask)
+{
+  bool bResult = TRUE;
+  int nbl, nbc;
+
+  if(pSource == NULL || pSource->nChannels != 1 || pSource->depth != IPL_DEPTH_8U)
+    bResult = FALSE;
+
+  if(bResult)
+  {
+    nbl = pSource->height;
+    nbc = pSource->width;
+    
+    if(pBackground == NULL || pBackground->width != nbc || pBackground->height != nbl || pBackground->imageSize != pSource->imageSize)
+      bResult = FALSE;
+    
+    if(pMotionMask == NULL || pMotionMask->width != nbc || pMotionMask->height != nbl || pMotionMask->imageSize != pSource->imageSize)
+      bResult = FALSE;
+  }
+
+  return bResult;
+}
+
+int TBackground::UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask)
+{
+  return 0;
+}
+
+IplImage *TBackground::CreateTestImg()
+{
+  IplImage *pImage = cvCreateImage(cvSize(256, 256), IPL_DEPTH_8U, 3);
+
+  if(pImage != NULL)
+    cvSetZero(pImage);
+
+  return pImage;
+}
+
+int TBackground::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd)
+{
+  int nErr = 0;
+  CvScalar Color;
+  unsigned char *ptr;
+  int l, c;
+
+  if(pTest == NULL || !isInitOk(pSource, pBackground, pSource))
+    nErr = 1;
+
+  if(!nErr)
+  {
+    if(pTest->width != 256 || pTest->height != 256 || pTest->nChannels != 3)
+      nErr = 1;
+
+    if(nX < 0 || nX > pSource->width || nY < 0 || nY > pSource->height)
+      nErr = 1;
+
+    switch(nInd)
+    {
+      case 0 : Color = cvScalar(128, 0, 0); break;
+      case 1 : Color = cvScalar(0, 128, 0); break;
+      case 2 : Color = cvScalar(0, 0, 128); break;
+      default : nErr = 1;
+    }
+  }
+
+  if(!nErr)
+  {
+    // recupere l'indice de la colonne
+    ptr = (unsigned char *)(pTest->imageData);
+    c = *ptr;
+    
+    // efface la colonne
+    cvLine(pTest, cvPoint(c, 0), cvPoint(c, 255), cvScalar(0));
+    *ptr += 1;
+
+    //recupere la couleur du fond
+    ptr = (unsigned char *)(pBackground->imageData + pBackground->widthStep * nY);
+    ptr += nX;
+    l = *ptr;
+
+    // dessine la couleur
+    cvLine(pTest, cvPoint(c, l - 5), cvPoint(c, l + 5), Color);
+
+    //recupere la couleur du point
+    ptr = (unsigned char *)(pSource->imageData + pSource->widthStep * nY);
+    ptr += nX;
+    l = *ptr;
+
+    // dessine la couleur
+    ptr = (unsigned char *)(pTest->imageData + pTest->widthStep * l);
+    ptr += (c * 3) + nInd;
+    *ptr = 255;
+  }
+
+  return nErr;
+}
diff --git a/package_bgs/av/TBackground.h b/package_bgs/av/TBackground.h
new file mode 100644
index 0000000000000000000000000000000000000000..974cab955cdddca8fa8bd1e59345544533eb7125
--- /dev/null
+++ b/package_bgs/av/TBackground.h
@@ -0,0 +1,51 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*  TBackground.h
+*  Framework
+*
+*  Created by Robinault Lionel on 07/12/11.
+*
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+class TBackground
+{
+public:
+  TBackground(void);
+  virtual ~TBackground(void);
+
+  virtual void Clear(void);
+  virtual void Reset(void);
+
+  virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+  virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd);
+  virtual IplImage *CreateTestImg();
+
+  virtual int GetParameterCount(void);
+  virtual std::string GetParameterName(int nInd);
+  virtual std::string GetParameterValue(int nInd);
+  virtual int SetParameterValue(int nInd, std::string csNew);
+
+protected:
+  virtual int Init(IplImage * pSource);
+  virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+};
diff --git a/package_bgs/av/TBackgroundVuMeter.cpp b/package_bgs/av/TBackgroundVuMeter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..45976213a3a0ff23f7d855d4f5977b966824d04d
--- /dev/null
+++ b/package_bgs/av/TBackgroundVuMeter.cpp
@@ -0,0 +1,380 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*  TBackgroundVuMeter.cpp
+*  Framework
+*
+*  Created by Robinault Lionel on 07/12/11.
+*
+*/
+#include "TBackgroundVuMeter.h"
+
+#define PROCESS_PAR_COUNT 3
+
+TBackgroundVuMeter::TBackgroundVuMeter(void)
+  : m_pHist(NULL)
+  , m_nBinSize(8)
+  , m_nBinCount(0)
+  , m_fAlpha(0.995)
+  , m_fThreshold(0.03)
+  , m_nCount(0)
+{
+  std::cout << "TBackgroundVuMeter()" << std::endl;
+}
+
+TBackgroundVuMeter::~TBackgroundVuMeter(void)
+{
+  Clear();
+  std::cout << "~TBackgroundVuMeter()" << std::endl;
+}
+
+void TBackgroundVuMeter::Clear(void)
+{
+  int i;
+
+  TBackground::Clear();
+
+  if(m_pHist != NULL)
+  {
+    for(i = 0; i < m_nBinCount; ++i)
+    {
+      if(m_pHist[i] != NULL)
+        cvReleaseImage(&m_pHist[i]);
+    }
+
+    delete m_pHist;
+    m_pHist = NULL;
+    m_nBinCount = 0;
+  }
+
+  m_nCount = 0;
+}
+
+void TBackgroundVuMeter::Reset(void)
+{
+  int i;
+  float fVal = 0.0;
+
+  TBackground::Reset();
+
+  if(m_pHist != NULL)
+  {
+    //		fVal = (m_nBinCount != 0) ? (float)(1.0 / (double)m_nBinCount) : (float)0.0;
+    fVal = 0.0;
+
+    for(i = 0; i < m_nBinCount; ++i)
+    {
+      if(m_pHist[i] != NULL)
+      {
+        cvSetZero(m_pHist[i]);
+        cvAddS(m_pHist[i], cvScalar(fVal), m_pHist[i]);
+      }
+    }
+  }
+
+  m_nCount = 0;
+}
+
+int TBackgroundVuMeter::GetParameterCount(void)
+{
+  return TBackground::GetParameterCount() + PROCESS_PAR_COUNT;
+}
+
+std::string TBackgroundVuMeter::GetParameterName(int nInd)
+{
+  std::string csResult;
+  int nNb;
+
+  nNb = TBackground::GetParameterCount();
+
+  if(nInd >= nNb)
+  {
+    nInd -= nNb;
+
+    switch(nInd)
+    {
+    case 0 : csResult = "Bin size"; break;
+    case 1 : csResult = "Alpha"; break;
+    case 2 : csResult = "Threshold"; break;
+    }
+  }
+  else 
+    csResult = TBackground::GetParameterName(nInd);
+
+  return csResult;
+}
+
+std::string TBackgroundVuMeter::GetParameterValue(int nInd)
+{
+  std::string csResult;
+  int nNb;
+
+  nNb = TBackground::GetParameterCount();
+
+  if(nInd >= nNb)
+  {
+    nInd -= nNb;
+
+    char buff[100];
+    
+    switch(nInd)
+    {
+      case 0 : sprintf(buff, "%d", m_nBinSize); break;
+      case 1 : sprintf(buff, "%.3f", m_fAlpha); break;
+      case 2 : sprintf(buff, "%.2f", m_fThreshold); break;
+    }
+
+    csResult = buff;
+  }
+  else 
+    csResult = TBackground::GetParameterValue(nInd);
+
+  return csResult;
+}
+
+int TBackgroundVuMeter::SetParameterValue(int nInd, std::string csNew)
+{
+  int nErr = 0;
+
+  int nNb;
+
+  nNb = TBackground::GetParameterCount();
+
+  if(nInd >= nNb)
+  {
+    nInd -= nNb;
+
+    switch(nInd)
+    {
+      case 0 : SetBinSize(atoi(csNew.c_str())); break;
+      case 1 : SetAlpha(atof(csNew.c_str())); break;
+      case 2 : SetThreshold(atof(csNew.c_str())); break;
+      default : nErr = 1;
+    }
+  }
+  else 
+    nErr = TBackground::SetParameterValue(nInd, csNew);
+
+  return nErr;
+}
+
+int TBackgroundVuMeter::Init(IplImage * pSource)
+{
+  int nErr = 0;
+  int i;
+  int nbl, nbc;
+
+  Clear();
+
+  nErr = TBackground::Init(pSource);
+
+  if(pSource == NULL)
+    nErr = 1;
+
+  // calcul le nb de bin
+  if(!nErr)
+  {
+    nbl = pSource->height;
+    nbc = pSource->width;
+    m_nBinCount = (m_nBinSize != 0) ? 256 / m_nBinSize : 0;
+
+    if(m_nBinCount <= 0 || m_nBinCount > 256)
+      nErr = 1;
+  }
+
+  // creation du tableau de pointeur
+  if(!nErr)
+  {
+    m_pHist = new IplImage *[m_nBinCount];
+
+    if(m_pHist == NULL)
+      nErr = 1;
+  }
+
+  // creation des images
+  if(!nErr)
+  {
+    for(i = 0; i < m_nBinCount; ++i)
+    {
+      m_pHist[i] = cvCreateImage(cvSize(nbc, nbl), IPL_DEPTH_32F, 1);
+
+      if(m_pHist[i] == NULL)
+        nErr = 1;
+    }
+  }
+
+  if(!nErr) 
+    Reset();
+  else
+    Clear();
+
+  return nErr;
+}
+
+bool TBackgroundVuMeter::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask)
+{
+  bool bResult = TRUE;
+  int i;
+  int nbl, nbc;
+
+  bResult = TBackground::isInitOk(pSource, pBackground, pMotionMask);
+
+  if(pSource == NULL)
+    bResult = FALSE;
+
+  if(m_nBinSize == 0)
+    bResult = FALSE;
+
+  if(bResult)
+  {
+    i = (m_nBinSize != 0) ? 256 / m_nBinSize : 0;
+
+    if(i != m_nBinCount || m_pHist == NULL)
+      bResult = FALSE;
+  }
+
+  if(bResult)
+  {
+    nbl = pSource->height;
+    nbc = pSource->width;
+
+    for(i = 0; i < m_nBinCount; ++i)
+    {
+      if(m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl)
+        bResult = FALSE;
+    }
+  }
+
+  return bResult;
+}
+
+int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackground, IplImage *pMotionMask)
+{
+  int nErr = 0;
+  int i, l, c, nbl, nbc;
+  unsigned char *ptrs, *ptrb, *ptrm;
+  float *ptr1, *ptr2;
+  unsigned char v;
+
+  if(!isInitOk(pSource, pBackground, pMotionMask))
+    nErr = Init(pSource);
+  
+  if(!nErr)
+  {
+    m_nCount++;
+    nbc = pSource->width;
+    nbl = pSource->height;
+    v = m_nBinSize;
+
+    // multiplie tout par alpha
+    for(i = 0; i < m_nBinCount; ++i)
+      cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0);
+
+    for(l = 0; l < nbl; ++l)
+    {
+      ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l);
+      ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l);
+      ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l);
+
+      for(c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++)
+      {
+        // recherche le bin � augmenter
+        i = *ptrs / v;
+        
+        if(i < 0 || i >= m_nBinCount)
+          i = 0;
+        
+        ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
+        ptr1 += c;
+
+        *ptr1 += (float)(1.0 - m_fAlpha);
+        *ptrm = (*ptr1 < m_fThreshold) ? 255 : 0;
+
+        // recherche le bin du fond actuel
+        i = *ptrb / v;
+        
+        if(i < 0 || i >= m_nBinCount)
+          i = 0;
+        
+        ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l);
+        ptr2 += c;
+
+        if(*ptr2 < *ptr1)
+          *ptrb = *ptrs;
+      }
+    }
+
+    if(m_nCount < 5)
+      cvSetZero(pMotionMask);
+  }
+
+  return nErr;
+}
+
+IplImage *TBackgroundVuMeter::CreateTestImg()
+{
+  IplImage *pImage = NULL;
+
+  if(m_nBinCount > 0)
+    pImage = cvCreateImage(cvSize(m_nBinCount, 100), IPL_DEPTH_8U, 3);
+
+  if(pImage != NULL)
+    cvSetZero(pImage);
+
+  return pImage;
+}
+
+int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd)
+{
+  int nErr = 0;
+  int i, nbl, nbc;
+  float *ptrf;
+
+  if(pTest == NULL || !isInitOk(pSource, pBackground, pSource)) 
+    nErr = 1;
+
+  if(!nErr)
+  {
+    nbl = pTest->height;
+    nbc = pTest->width;
+
+    if(nbl != 100 || nbc != m_nBinCount) 
+      nErr = 1;
+
+    if(nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height)
+      nErr = 1;
+  }
+
+  if(!nErr)
+  {
+    cvSetZero(pTest);
+
+    for(i = 0; i < m_nBinCount; ++i)
+    {
+      ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY);
+      ptrf += nX;
+
+      if(*ptrf >= 0 || *ptrf <= 1.0) {
+        cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0));
+      }
+    }
+
+    cvLine(pTest, cvPoint(0, (int)(100.0 * (1.0 - m_fThreshold))), cvPoint(m_nBinCount, (int)(100.0 * (1.0 - m_fThreshold))), cvScalar(0, 128, 0));
+  }
+
+  return nErr;
+}
diff --git a/package_bgs/av/TBackgroundVuMeter.h b/package_bgs/av/TBackgroundVuMeter.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a19324f08c8d20b4bb2fd972a9920e73b2adae8
--- /dev/null
+++ b/package_bgs/av/TBackgroundVuMeter.h
@@ -0,0 +1,67 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+*  TBackgroundVuMeter.h
+*  Framework
+*
+*  Created by Robinault Lionel on 07/12/11.
+*
+*/
+#pragma once
+
+#include "TBackground.h"
+
+class TBackgroundVuMeter : public TBackground
+{
+public:
+  TBackgroundVuMeter(void);
+  virtual ~TBackgroundVuMeter(void);
+
+  virtual void Clear(void);
+  virtual void Reset(void);
+
+  virtual int UpdateBackground(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+
+  virtual IplImage *CreateTestImg();
+  virtual int UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage *pTest, int nX, int nY, int nInd);
+
+  virtual int GetParameterCount(void);
+  virtual std::string GetParameterName(int nInd);
+  virtual std::string GetParameterValue(int nInd);
+  virtual int SetParameterValue(int nInd, std::string csNew);
+
+  inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ?  nNew : 8; }
+  inline double GetBinSize() { return m_nBinSize; }
+
+  inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ?  fNew : 0.995; }
+  inline double GetAlpha() { return m_fAlpha; }
+
+  inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ?  fNew : 0.03; }
+  inline double GetThreshold() { return m_fThreshold; }
+
+protected:
+  IplImage **m_pHist;
+
+  int m_nBinCount;
+  int m_nBinSize;
+  int m_nCount;
+  double m_fAlpha;
+  double m_fThreshold;
+
+  virtual int Init(IplImage * pSource);
+  virtual bool isInitOk(IplImage * pSource, IplImage *pBackground, IplImage *pMotionMask);
+};
diff --git a/package_bgs/av/VuMeter.cpp b/package_bgs/av/VuMeter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..29a1477f536a06058f76bc51384c12712b0db761
--- /dev/null
+++ b/package_bgs/av/VuMeter.cpp
@@ -0,0 +1,116 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "VuMeter.h"
+
+VuMeter::VuMeter() : firstTime(true), showOutput(true), enableFilter(true), binSize(8), alpha(0.995), threshold(0.03)
+{
+  std::cout << "VuMeter()" << std::endl;
+}
+
+VuMeter::~VuMeter()
+{
+  cvReleaseImage(&mask);
+  cvReleaseImage(&background);
+  cvReleaseImage(&gray);
+
+  std::cout << "~VuMeter()" << std::endl;
+}
+
+void VuMeter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+  else
+    frame = new IplImage(img_input);
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    bgs.SetAlpha(alpha);
+    bgs.SetBinSize(binSize);
+    bgs.SetThreshold(threshold);
+
+    gray = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
+    cvCvtColor(frame,gray,CV_RGB2GRAY);
+
+    background = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1);
+    cvCopy(gray, background);
+
+    mask = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1);
+    cvZero(mask);
+
+    saveConfig();
+  }
+  else
+    cvCvtColor(frame,gray,CV_RGB2GRAY);
+  
+  bgs.UpdateBackground(gray,background,mask);
+  cv::Mat img_foreground(mask);
+  cv::Mat img_bkg(background);
+
+  if(enableFilter)
+  {
+    cv::erode(img_foreground,img_foreground,cv::Mat());
+    cv::medianBlur(img_foreground, img_foreground, 5);
+  }
+
+  if(showOutput)
+  {
+    if(!img_foreground.empty())
+      cv::imshow("VuMeter", img_foreground);
+    
+    if(!img_bkg.empty())
+      cv::imshow("VuMeter Bkg Model", img_bkg);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_bkg.copyTo(img_bgmodel);
+  
+  delete frame;
+  firstTime = false;
+}
+
+void VuMeter::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/VuMeter.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "enableFilter", enableFilter);
+  
+  cvWriteInt(fs, "binSize", binSize);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteReal(fs, "threshold", threshold);
+  
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void VuMeter::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/VuMeter.xml", 0, CV_STORAGE_READ);
+  
+  enableFilter = cvReadIntByName(fs, 0, "enableFilter", true);
+  
+  binSize = cvReadIntByName(fs, 0, "binSize", 8);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.995);
+  threshold = cvReadRealByName(fs, 0, "threshold", 0.03);
+  
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/av/VuMeter.h b/package_bgs/av/VuMeter.h
new file mode 100644
index 0000000000000000000000000000000000000000..7884ff68aa5ac41eb42225b1d6defa2ddcda3b58
--- /dev/null
+++ b/package_bgs/av/VuMeter.h
@@ -0,0 +1,53 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "TBackgroundVuMeter.h"
+#include "../IBGS.h"
+
+class VuMeter : public IBGS
+{
+private:
+  TBackgroundVuMeter bgs;
+
+  IplImage *frame;
+  IplImage *gray;
+  IplImage *background;
+  IplImage *mask;
+  
+  bool firstTime;
+  bool showOutput;
+  bool enableFilter;
+  
+  int binSize;
+  double alpha;
+  double threshold;
+  
+public:
+  VuMeter();
+  ~VuMeter();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/package_bgs/ck/LbpMrf.cpp b/package_bgs/ck/LbpMrf.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f3d068c253505783976837916c3e4611bbed63bb
--- /dev/null
+++ b/package_bgs/ck/LbpMrf.cpp
@@ -0,0 +1,87 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+
+Csaba, Kertész: Texture-Based Foreground Detection, International Journal of Signal Processing,
+Image Processing and Pattern Recognition (IJSIP), Vol. 4, No. 4, 2011.
+
+*/
+#include "LbpMrf.h"
+
+#include "MotionDetection.hpp"
+
+LbpMrf::LbpMrf() : firstTime(true), Detector(NULL), showOutput(true)
+{
+  std::cout << "LbpMrf()" << std::endl;
+  Detector = new MotionDetection();
+  Detector->SetMode(MotionDetection::md_LBPHistograms);
+}
+
+LbpMrf::~LbpMrf()
+{
+  std::cout << "~LbpMrf()" << std::endl;
+  delete Detector;
+  Detector = NULL;
+}
+
+void LbpMrf::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    saveConfig();
+  }
+
+  IplImage TempImage(img_input);
+  MEImage InputImage(img_input.cols, img_input.rows, img_input.channels());
+  MEImage OutputImage(img_input.cols, img_input.rows, img_input.channels());
+
+  InputImage.SetIplImage((void*)&TempImage);
+
+  Detector->DetectMotions(InputImage);
+  Detector->GetMotionsMask(OutputImage);
+  img_output = (IplImage*)OutputImage.GetIplImage();
+  bitwise_not(img_output, img_bgmodel);
+
+  if(showOutput)
+  {
+    cv::imshow("LBP-MRF FG", img_output);
+    cv::imshow("LBP-MRF BG", img_bgmodel);
+  }
+
+  firstTime = false;
+}
+
+void LbpMrf::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LbpMrf.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void LbpMrf::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LbpMrf.xml", 0, CV_STORAGE_READ);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/ck/LbpMrf.h b/package_bgs/ck/LbpMrf.h
new file mode 100644
index 0000000000000000000000000000000000000000..6fd72673a16d0f649b58d08b9f16b6ca5b786c2d
--- /dev/null
+++ b/package_bgs/ck/LbpMrf.h
@@ -0,0 +1,44 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <opencv2/opencv.hpp>
+
+#include "../IBGS.h"
+
+class MotionDetection;
+
+class LbpMrf : public IBGS
+{
+private:
+  bool firstTime;
+  MotionDetection* Detector;
+  cv::Mat img_foreground;
+  cv::Mat img_segmentation;
+  bool showOutput;
+
+public:
+  LbpMrf();
+  ~LbpMrf();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/package_bgs/ck/MEDefs.cpp b/package_bgs/ck/MEDefs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..93473537cbd5b7de0ce6ffc1dcc17f380004b91f
--- /dev/null
+++ b/package_bgs/ck/MEDefs.cpp
@@ -0,0 +1,40 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "MEDefs.hpp"
+
+#include <math.h>
+
+float MERound(float number)
+{
+	double FracPart = 0.0;
+	double IntPart = 0.0;
+	float Ret = 0.0;
+
+	FracPart = modf((double)number, &IntPart);
+	if (number >= 0)
+	{
+	  Ret = (float)(FracPart >= 0.5 ? IntPart+1 : IntPart);
+	} else {
+	  Ret = (float)(FracPart <= -0.5 ? IntPart-1 : IntPart);
+	}
+	return Ret;
+}
diff --git a/package_bgs/ck/MEDefs.hpp b/package_bgs/ck/MEDefs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d5bc24637555a67639842a9269ea758d605db9dd
--- /dev/null
+++ b/package_bgs/ck/MEDefs.hpp
@@ -0,0 +1,83 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef MEDefs_hpp
+#define MEDefs_hpp
+
+/**
+ *  @addtogroup mindeye
+ *  @{
+ */
+
+/// Pi value
+#ifndef ME_PI_VALUE
+#define ME_PI_VALUE 3.14159265
+#endif
+
+/*! Process state */
+typedef enum {
+  ps_Min = 0,                /*!< Minimum value */
+  ps_Uninitialized = ps_Min, /*!< Uninitialized state */
+  ps_Initialized,            /*!< Initialized state */
+  ps_InProgress,             /*!< In progress state */
+  ps_Successful,             /*!< Successful state */
+  ps_Max = ps_Successful     /*!< Maximum value */
+} MEProcessStateType;
+
+template <typename T>
+const T& MEMin(const T& a, const T& b)
+{
+  if (a < b)
+    return a;
+  return b;
+}
+
+template <typename T>
+const T& MEMax(const T& a, const T& b)
+{
+  if (a < b)
+    return b;
+  return a;
+}
+
+template <typename T>
+const T& MEBound(const T& min, const T& val, const T& max)
+{
+  return MEMax(min, MEMin(max, val));
+}
+
+/*!
+ * @brief Round a float number
+ *
+ * @param number number to round
+ *
+ * @return New float number
+ *
+ * This method rounds a float number, if the fraction is .5 or lower
+ * then it rounds down, otherwise up.
+ *
+ */
+
+float MERound(float number);
+
+/** @} */
+
+#endif
diff --git a/package_bgs/ck/MEHistogram.cpp b/package_bgs/ck/MEHistogram.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..126fd259fefb6ee853fe354235972cd6a4e964ff
--- /dev/null
+++ b/package_bgs/ck/MEHistogram.cpp
@@ -0,0 +1,508 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ *  Some histogram stretch codes are based on how Gimp does it, the same
+ *  GPL 2 license applies for the following authors:
+ *
+ *  The GIMP -- an image manipulation program
+ *  Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ */
+
+#include "MEHistogram.hpp"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <cv.h>
+#else
+#include <opencv/cv.h>
+#endif
+
+#include "MEDefs.hpp"
+#include "MEImage.hpp"
+
+MEHistogram::MEHistogram()
+{
+  Clear();
+}
+
+
+MEHistogram::~MEHistogram()
+{
+}
+
+
+void MEHistogram::Clear()
+{
+  memset(&HistogramData, 0, 256*sizeof(int));
+}
+
+
+bool MEHistogram::operator==(MEHistogram& histogram) const
+{
+  bool ret = true;
+
+  for (int i = 255; i >= 0; --i)
+  {
+    if (HistogramData[i] != histogram.HistogramData[i])
+    {
+      ret = false;
+      break;
+    }
+  }
+  return ret;
+}
+
+
+void MEHistogram::Calculate(MEImage& image, int channel, HistogramType mode)
+{
+  int Channel = (channel < 1) ? 1 : ((channel > image.GetLayers()) ? image.GetLayers() : channel);
+
+  if (mode == h_Overwrite)
+  {
+    Clear();
+  }
+
+  unsigned char *ImageData = image.GetImageData();
+  int rowStart = 0;
+
+  for (int i = image.GetHeight()-1; i >= 0; i--)
+  {
+    for (int i1 = (image.GetWidth()-1)*image.GetLayers()+Channel-1; i1 >= Channel-1; i1 -= image.GetLayers())
+    {
+      HistogramData[ImageData[rowStart+i1]]++;
+    }
+    rowStart += image.GetRowWidth();
+  }
+}
+
+
+void MEHistogram::Calculate(MEImage& image, HistogramType mode)
+{
+  if (mode == h_Overwrite)
+  {
+    Clear();
+  }
+
+  unsigned char *ImageData = image.GetImageData();
+  int RowStart = 0;
+  int RowWidth = image.GetRowWidth();
+
+  for (int i = image.GetHeight()-1; i >= 0; i--)
+  {
+    for (int i1 = image.GetWidth()*image.GetLayers()-1; i1 >= 0; i1--)
+    {
+      HistogramData[ImageData[RowStart+i1]]++;
+    }
+    RowStart += RowWidth;
+  }
+}
+
+
+void MEHistogram::Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1)
+{
+  int Channel = (channel < 1) ? 1 : ((channel > image.GetLayers()) ? image.GetLayers() : channel);
+  unsigned char *ImageData = image.GetImageData();
+  int RowStart = 0;
+  int RowWidth = image.GetRowWidth();
+  int X0 = x0 > x1 ? x1 : x0;
+  int Y0 = y0 > y1 ? y1 : y0;
+  int X1 = x0 < x1 ? x1 : x0;
+  int Y1 = y0 < y1 ? y1 : y0;
+
+  Clear();
+
+  // Compute the correct region coordinates and check them
+  X0 = X0 < 0 ? 0 : X0;
+  Y0 = Y0 < 0 ? 0 : Y0;
+  X1 = X1 > image.GetWidth()-1 ? image.GetWidth()-1 : X1;
+  Y1 = Y1 > image.GetHeight()-1 ? image.GetHeight()-1 : Y1;
+  RowStart = Y0*image.GetRowWidth();
+
+  for (int i = Y1; i >= Y0; --i)
+  {
+    for (int i1 = X1*image.GetLayers()+Channel-1; i1 >= X0*image.GetLayers()+Channel-1;
+         i1 -= image.GetLayers())
+    {
+      HistogramData[ImageData[RowStart+i1]]++;
+    }
+    RowStart += RowWidth;
+  }
+}
+
+
+int MEHistogram::GetPeakIndex() const
+{
+  int PeakIndex = 0;
+  int PeakValue = 0;
+
+  for (int i = 0; i < 256; i++)
+  {
+    if (PeakValue < HistogramData[i])
+    {
+      PeakValue = HistogramData[i];
+      PeakIndex = i;
+    }
+  }
+  return PeakIndex;
+}
+
+
+int MEHistogram::GetLowestLimitIndex(int threshold) const
+{
+  int MinIndex = 0;
+
+  for (int i = 0; i < 256; i++)
+  {
+    if (threshold <= HistogramData[i])
+    {
+      MinIndex = i;
+      break;
+    }
+  }
+  return MinIndex;
+}
+
+
+int MEHistogram::GetHighestLimitIndex(int threshold) const
+{
+  int MaxIndex = 255;
+
+  for (int i = 255; i >= 0; i--)
+  {
+    if (threshold <= HistogramData[i])
+    {
+      MaxIndex = i;
+      break;
+    }
+  }
+  return MaxIndex;
+}
+
+
+int MEHistogram::GetPowerAmount(int minindex, int maxindex) const
+{
+  int ValueAmount = 0;
+  int MinIndex = (minindex > 255) ? 255 : ((minindex < 0) ? 0 : minindex);
+  int MaxIndex = (maxindex > 255) ? 255 : ((maxindex < 0) ? 0 : maxindex);
+
+  if (MinIndex > MaxIndex)
+  {
+    int TempInt = MinIndex;
+    MinIndex = MaxIndex;
+    MaxIndex = TempInt;
+  }
+
+  for (int i = MinIndex; i <= MaxIndex; i++)
+  {
+    ValueAmount += HistogramData[i];
+  }
+  return ValueAmount;
+}
+
+
+int MEHistogram::GetCentroidIndex() const
+{
+  int ValueAmount = GetPowerAmount(0, 255);
+  int WeightedValueAmount = 1;
+  int CentroidIndex = 0;
+
+  // Calculate the normal and weighted amount of histogram values
+  for (int i = 0; i < 256; i++)
+  {
+    WeightedValueAmount += i*HistogramData[i];
+  }
+  // Calculate the centroid point of the histogram
+  CentroidIndex = WeightedValueAmount / ValueAmount;
+  return CentroidIndex;
+}
+
+
+bool MEHistogram::Stretch(StretchType mode)
+{
+  int MinIndex = -1;
+  int MaxIndex = -1;
+  int Percent = -1;
+  double Percentage = 0.0;
+  double NextPercentage = 0.0;
+  double Count = 0.0;
+  double NewCount = 0.0;
+  bool Ret = true;
+
+  switch (mode)
+  {
+    case s_OwnMode:
+      Percent = 20;
+      MinIndex = GetLowestLimitIndex(Percent);
+      MaxIndex = GetHighestLimitIndex(Percent);
+
+      while ((abs(MaxIndex-MinIndex) < 52) && (Percent > 1))
+      {
+        Percent = Percent / 2;
+        MinIndex = GetLowestLimitIndex(Percent);
+        MaxIndex = GetHighestLimitIndex(Percent);
+
+        // The calculation gives wrong answer back
+        if (MinIndex == 0 && MaxIndex == 255)
+        {
+          MinIndex = 128;
+          MaxIndex = 128;
+          Ret = false;
+        }
+      }
+      break;
+
+    case s_GimpMode:
+      Count = GetPowerAmount(0, 255);
+      NewCount = 0;
+
+      for (int i = 0; i < 255; i++)
+      {
+        double Value = 0.0;
+        double NextValue = 0.0;
+
+        Value = HistogramData[i];
+        NextValue = HistogramData[i+1];
+        NewCount += Value;
+        Percentage = NewCount / Count;
+        NextPercentage = (NewCount+NextValue) / Count;
+
+        if (fabs(Percentage-0.006) < fabs(NextPercentage-0.006))
+        {
+          MinIndex = i+1;
+          break;
+        }
+      }
+      NewCount = 0.0;
+      for (int i = 255; i > 0; i--)
+      {
+        double Value = 0.0;
+        double NextValue = 0.0;
+
+        Value = HistogramData[i];
+        NextValue = HistogramData[i-1];
+        NewCount += Value;
+        Percentage = NewCount / Count;
+        NextPercentage = (NewCount+NextValue) / Count;
+
+        if (fabs(Percentage-0.006) < fabs(NextPercentage-0.006))
+        {
+          MaxIndex = i-1;
+          break;
+        }
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  if (MaxIndex <= MinIndex)
+  {
+    MinIndex = 0;
+    MaxIndex = 255;
+    Ret = false;
+  }
+  if (MaxIndex-MinIndex <= 10 ||
+      (MaxIndex-MinIndex <= 20 && (float)GetPowerAmount(MinIndex, MaxIndex) / GetPowerAmount(0, 255) < 0.20))
+  {
+    MinIndex = 0;
+    MaxIndex = 255;
+    Ret = false;
+  }
+  if (Ret)
+  {
+    unsigned char TransformedHistogram[256];
+
+    for (int i = 0; i < 256; ++i)
+    {
+      TransformedHistogram[i] = (unsigned char)MEBound(0, 255*(i-MinIndex) / (MaxIndex-MinIndex), 255);
+    }
+    for (int i = 0; i < 256; ++i)
+    {
+      HistogramData[i] = TransformedHistogram[i];
+    }
+  }
+  return Ret;
+}
+
+
+MEHistogramTransform::MEHistogramTransform() : ChannelMode(p_SeparateChannels),
+StretchMode(MEHistogram::s_GimpMode), DiscreteStretchingDone(false)
+{
+}
+
+
+MEHistogramTransform::~MEHistogramTransform()
+{
+}
+
+
+void MEHistogramTransform::HistogramStretch(MEImage& image)
+{
+  SetStretchProcessingMode(p_SeparateChannels, MEHistogram::s_GimpMode);
+  HistogramStretch(image, t_Continuous);
+}
+
+
+void MEHistogramTransform::HistogramStretch(MEImage& image, TransformType time_mode)
+{
+  if (time_mode == t_Continuous)
+  {
+    DiscreteStretchingDone = false;
+  }
+
+  if (ChannelMode == p_Average || image.GetLayers() == 1)
+  {
+    if (time_mode == t_Continuous || (time_mode == t_Discrete && !DiscreteStretchingDone))
+    {
+      RedChannel.Calculate(image, 1, MEHistogram::h_Overwrite);
+
+      for (int l = 1; l < image.GetLayers(); l++)
+      {
+        RedChannel.Calculate(image, l+1, MEHistogram::h_Add);
+      }
+      RedChannel.Stretch(StretchMode);
+      if (time_mode == t_Discrete && !DiscreteStretchingDone)
+      {
+        DiscreteStretchingDone = true;
+      }
+    }
+    unsigned char *ImageData = image.GetImageData();
+    int RowStart = 0;
+    int RowWidth = image.GetRowWidth();
+
+    for (int i = image.GetHeight()-1; i >= 0; i--)
+    {
+      for (int i1 = image.GetWidth()*image.GetLayers()-1; i1 >= 0; i1--)
+      {
+        ImageData[RowStart+i1] = RedChannel.HistogramData[ImageData[RowStart+i1]];
+      }
+      RowStart += RowWidth;
+    }
+  } else
+  if (ChannelMode == p_SeparateChannels)
+  {
+    if (time_mode == t_Continuous || (time_mode == t_Discrete && !DiscreteStretchingDone))
+    {
+      RedChannel.Calculate(image, 1, MEHistogram::h_Overwrite);
+      GreenChannel.Calculate(image, 2, MEHistogram::h_Overwrite);
+      BlueChannel.Calculate(image, 3, MEHistogram::h_Overwrite);
+      RedChannel.Stretch(StretchMode);
+      GreenChannel.Stretch(StretchMode);
+      BlueChannel.Stretch(StretchMode);
+      if (time_mode == t_Discrete && !DiscreteStretchingDone)
+      {
+        DiscreteStretchingDone = true;
+      }
+    }
+    unsigned char *ImageData = image.GetImageData();
+    int RowStart = 0;
+    int RowWidth = image.GetRowWidth();
+
+    for (int i = image.GetHeight()-1; i >= 0; i--)
+    {
+      for (int i1 = image.GetWidth()*image.GetLayers()-3; i1 >= 0; i1 -= 3)
+      {
+        ImageData[RowStart+i1] = RedChannel.HistogramData[ImageData[RowStart+i1]];
+        ImageData[RowStart+i1+1] = GreenChannel.HistogramData[ImageData[RowStart+i1+1]];
+        ImageData[RowStart+i1+2] = BlueChannel.HistogramData[ImageData[RowStart+i1+2]];
+      }
+      RowStart += RowWidth;
+    }
+  }
+}
+
+
+void MEHistogramTransform::HistogramEqualize(MEImage& image)
+{
+  DiscreteStretchingDone = false;
+  IplImage* cvDest8bitImg = NULL;
+  IplImage* cvDestImg = NULL;
+
+  switch (image.GetLayers())
+  {
+    case 1:
+      // Grayscale image
+      cvDest8bitImg = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1);
+      cvEqualizeHist((IplImage*)image.GetIplImage(), cvDest8bitImg);
+      image.SetIplImage((void*)cvDest8bitImg);
+      cvReleaseImage(&cvDest8bitImg);
+      break;
+
+    case 3:
+      // RGB image
+      cvDestImg = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 3);
+      IplImage *cvR, *cvG, *cvB;
+
+      cvR = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1);
+      cvG = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1);
+      cvB = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1);
+
+      cvSplit((IplImage*)image.GetIplImage(), cvR, cvG, cvB, NULL);
+      cvEqualizeHist(cvR, cvR);
+      cvEqualizeHist(cvG, cvG);
+      cvEqualizeHist(cvB, cvB);
+      cvMerge(cvR, cvG, cvB, NULL, cvDestImg);
+
+      image.SetIplImage((void*)cvDestImg);
+      cvReleaseImage(&cvR);
+      cvReleaseImage(&cvG);
+      cvReleaseImage(&cvB);
+      cvReleaseImage(&cvDestImg);
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MEHistogramTransform::SetStretchProcessingMode(ProcessingType new_channel_mode,
+                                                    MEHistogram::StretchType new_stretch_mode)
+{
+  DiscreteStretchingDone = false;
+
+  switch(new_channel_mode)
+  {
+    case p_SeparateChannels:
+      ChannelMode = new_channel_mode;
+      break;
+
+    case p_Average:
+      ChannelMode = new_channel_mode;
+      break;
+
+    default:
+      break;
+  }
+
+  switch(new_stretch_mode)
+  {
+    case MEHistogram::s_OwnMode:
+      StretchMode = new_stretch_mode;
+      break;
+
+    case MEHistogram::s_GimpMode:
+      StretchMode = new_stretch_mode;
+      break;
+
+    default:
+      break;
+  }
+}
diff --git a/package_bgs/ck/MEHistogram.hpp b/package_bgs/ck/MEHistogram.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b2b47f00d44716df0b1307a3631992e8c7342b0
--- /dev/null
+++ b/package_bgs/ck/MEHistogram.hpp
@@ -0,0 +1,348 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef MEHistogram_hpp
+#define MEHistogram_hpp
+
+/**
+ *  @addtogroup mindeye
+ *  @{
+ */
+
+class MEImage;
+
+/**
+ * MEHistogram
+ * @brief The class provides basic histogram operations
+ */
+class MEHistogram
+{
+public:
+
+  /// Types of histogram calculation
+  typedef enum {
+    h_Min = 0,           /*!< Minimum value */
+    h_Overwrite = h_Min, /*!< Overwrite */
+    h_Add,               /*!< Add */
+    h_Max = h_Add        /*!< Maximum value */
+  } HistogramType;
+
+  /// Types of histogram stretching
+  typedef enum {
+    s_Min = 0,          /*!< Minimum value */
+    s_OwnMode = s_Min,  /*!< Own mode */
+    s_GimpMode,         /*!< Gimp mode */
+    s_Max = s_GimpMode  /*!< Maximum value */
+  } StretchType;
+
+  /// Constructor of class
+  MEHistogram();
+  /// Destructor of class
+  ~MEHistogram();
+
+  /*!
+   * @brief Clear histogram data
+   *
+   * Clear histogram data.
+   *
+   */
+
+  void Clear();
+
+  /*!
+   * @brief Equality (==) operator
+   *
+   * @param histogram Histogram to be compared
+   *
+   * @return True if the two histograms are equal.
+   *
+   * Compare two histograms.
+   *
+   */
+
+  bool operator==(MEHistogram& histogram) const;
+
+  /*!
+   * @brief Calculate the histogram of one color channel
+   *
+   * @param image Given image for the calculations
+   * @param channel Selected color channel for calculation (Range: 1..x)
+   * @param mode The mode of calculation.
+   *
+   * The method calculates the histograms of a color channel.
+   * There is two different type of the function:
+   *
+   * - h_Add: Add the data to the existing histogram.
+   * - h_Overwrite: Clear the histogram data before the
+   * calculation.
+   *
+   */
+
+  void Calculate(MEImage& image, int channel, HistogramType mode);
+
+  /*!
+   * @brief Calculate the average histogram of an image
+   *
+   * @param image Given image for the calculations
+   * @param mode Histogram calculation mode
+   *
+   * The method calculates the average histogram of an image.
+   *
+   */
+
+  void Calculate(MEImage& image, HistogramType mode = h_Overwrite);
+
+  /*!
+   * @brief Calculate the histogram of an image region
+   *
+   * @param image Given image for the calculations
+   * @param channel Selected color channel for calculation (Range: 1..x)
+   * @param x0 x0 coordinate of the region
+   * @param y0 y0 coordinate of the region
+   * @param x1 x1 coordinate of the region
+   * @param y1 y1 coordinate of the region
+   *
+   * The method calculates the average histogram of an image region
+   * (x0,y0)-(x1,y1).
+   *
+   */
+
+  void Calculate(MEImage& image, int channel, int x0, int y0, int x1, int y1);
+
+  /*!
+   * @brief Get the index of maximum value of the histogram
+   *
+   * @return Index number
+   *
+   * Function gives an index value back where is the highest
+   * peak of the histogram.
+   *
+   */
+
+  int GetPeakIndex() const;
+
+  /*!
+   * @brief Get the lowest histogram index with an threshold value
+   *
+   * @param threshold Specified threshold (in percent: 0..100 %)
+   *
+   * @return Index number
+   *
+   * Function gives the lowest index back whose value reaches
+   * an threshold value calculated by (counted pixel number /
+   * 10*threshold / 100).
+   *
+   */
+
+  int GetLowestLimitIndex(int threshold) const;
+
+  /*!
+   * @brief Get the highest histogram index with an threshold value
+   *
+   * @param threshold Specified threshold (in percent: 0..100 %)
+   *
+   * @return Index number
+   *
+   * Function gives the highest index back whose value reaches
+   * an threshold value calculated by (counted pixel number /
+   * 10*threshold / 100).
+   *
+   */
+
+  int GetHighestLimitIndex(int threshold) const;
+
+  /*!
+   * @brief Get the amount of the histogram values in an interval
+   *
+   * @param minindex Minimal index of the interval
+   * @param maxindex Maximal index of the interval
+   *
+   * @return Amount of the values
+   *
+   * Function calculates the amount of the histogram values
+   * in a given interval.
+   *
+   */
+
+  int GetPowerAmount(int min_index, int max_index) const;
+
+  /*!
+   * @brief Get index value of the centroid point of the histogram
+   *
+   * @return Index number
+   *
+   * Function calculates the centre of area of the histogram and
+   * gives the index number back.
+   *
+   */
+
+  int GetCentroidIndex() const;
+
+  /*!
+   * @brief Stretch the histogram
+   *
+   * @param mode Mode of the histogram stretching
+   *
+   * @return True if successful, otherwise false.
+   *
+   * The function selects and stretches the main power
+   * interval of the histogram. The following calculation
+   * modes are available:
+   *
+   * - s_OwnMode: The calculation of the power
+   * interval is selected by functions Histogram::GetHistogramLowestLimitIndex()
+   * and Histogram::GetHistogramHighestLimitIndex() where the
+   * threshold is 20, 10, 5, 2, 1 in order. The power range will
+   * be selected if the length is at least 52 long or the used
+   * threshold reaches the 1 value.
+   * - s_GimpMode: The minimum index of power interval is
+   * specified by the first fulfilled abs(percentage[i]-0.006) <
+   * fabs(percentage[i+1]-0.006) where the percentage[i] means
+   * the amount of the histogram values in the interval [0, i].
+   * The maximum index is specified by the first fulfilled
+   * (from the end of the histogram) abs(percentage[i]-0.006) <
+   * fabs(percentage[i-1]-0.006) where the percentage[i] means
+   * the amount of the histogram values in the interval [i, 255].
+   *
+   * The stretch operation is rejected if the power interval is
+   * less than 10 or less than 20 and the percentage[min_index, max_index]
+   * / percentage[0, 255] < 0.2.
+   *
+   */
+
+  bool Stretch(StretchType mode);
+
+  /// Histogram spectrum
+  int HistogramData[256];
+};
+
+
+/**
+ * MEHistogramTransform
+ * @brief The class provides histogram operations
+ */
+class MEHistogramTransform
+{
+public:
+  /// Types of histogram processing
+  typedef enum {
+    p_Min = 0,                   /*!< Minimum value */
+    p_SeparateChannels = p_Min, /*!< Separate channels */
+    p_Average,                   /*!< Average */
+    p_Max = p_Average           /*!< Maximum value */
+  } ProcessingType;
+
+  /// Types of histogram transformations
+  typedef enum {
+    t_Min = 0,             /*!< Minimum value */
+    t_Continuous = t_Min, /*!< Continuous */
+    t_Discrete,            /*!< Discrete */
+    t_Max = t_Discrete    /*!< Maximum value */
+  } TransformType;
+
+  /// Constructor of class
+  MEHistogramTransform();
+  /// Destructor of class
+  ~MEHistogramTransform();
+
+  /*!
+   * @brief Histogram stretching an image
+   *
+   * @param image Source image to stretch
+   *
+   * The function stretches the histogram of the given image with
+   * default parameters: process the color channels separately
+   * and continuously.
+   *
+   */
+
+  void HistogramStretch(MEImage& image);
+
+  /*!
+   * @brief Histogram stretching with specified parameters
+   *
+   * @param image Source image to stretch
+   * @param time_mode Mode of the histogram stretching
+   *
+   * The function transformations the histogram of the image.
+   * There is some different possibilities to make the operation:
+   *
+   * - t_Continuous: The function always stretches the
+   * image at each call of the method.
+   * - t_Discrete: A histogram is calculated at the first
+   * call of the function and all further images will be
+   * stretched by this initial histogram.
+   *
+   */
+
+  void HistogramStretch(MEImage& image, TransformType time_mode);
+
+  /*!
+   * @brief Histogram equalization on an image
+   *
+   * @param image Source image to equalize
+   *
+   * The source image is transformed by histogram
+   * equalization.
+   *
+   */
+
+  void HistogramEqualize(MEImage& image);
+
+  /*!
+   * @brief Set the process mode of the histogram transformation
+   *
+   * @param new_channel_mode New mode of processing channels
+   * @param new_stretch_mode New mode of histogram stretching
+   *
+   * The process mode of histogram transformation can be
+   * set by this method. Two process modes are available for
+   * processing channels:
+   *
+   * - p_SeparateChannels: The class processes the color channels
+   * separately.
+   * - p_Average: The color channels are averaged
+   * in the histogram operations.
+   *
+   * Two process modes are usable for histogram stretching:
+   * s_OwnMode and s_GimpMode. See Histogram::Stretch()
+   * for more details.
+   *
+   */
+
+  void SetStretchProcessingMode(ProcessingType new_channel_mode, MEHistogram::StretchType new_stretch_mode);
+
+private:
+  /// Type of the process of histograms
+  ProcessingType ChannelMode;
+  /// Stretch mode
+  MEHistogram::StretchType StretchMode;
+  /// Histograms for red, green and blue color channels
+  MEHistogram RedChannel, GreenChannel, BlueChannel;
+  /// Histogram for average calculation
+  MEHistogram AverageChannel;
+  /// Continuous histogram stretch is done already
+  bool DiscreteStretchingDone;
+};
+
+/** @} */
+
+#endif
diff --git a/package_bgs/ck/MEImage.cpp b/package_bgs/ck/MEImage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a625a9686d42ba27f63aa115ec9343ed2d63ea6
--- /dev/null
+++ b/package_bgs/ck/MEImage.cpp
@@ -0,0 +1,1472 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "MEImage.hpp"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <cv.h>
+#include <highgui.h>
+#else
+#include <opencv/cv.h>
+#include <opencv/highgui.h>
+#endif
+
+#include "MEDefs.hpp"
+
+#define ME_CAST_TO_IPLIMAGE(image_ptr) ((IplImage*)image_ptr)
+#define ME_RELEASE_IPLIMAGE(image_ptr) \
+  cvReleaseImage((IplImage**)&image_ptr); \
+  image_ptr = NULL;
+
+// RGB to YUV transform
+const float RGBtoYUVMatrix[3][3] =
+  {{ 0.299, 0.587, 0.114 },
+  { -0.147, -0.289, 0.436 },
+  { 0.615, -0.515, -0.100 }};
+
+// RGB to YIQ transform
+const float RGBtoYIQMatrix[3][3] =
+  {{ 0.299, 0.587, 0.114 },
+  { 0.596, -0.274, -0.322 },
+  { 0.212, -0.523, 0.311 }};
+
+MEImage::MEImage(int width, int height, int layers) : cvImg(NULL)
+{
+  _Init(width, height, layers);
+}
+
+
+MEImage::MEImage(const MEImage& other) : cvImg(NULL)
+{
+  _Copy(other);
+}
+
+
+MEImage::~MEImage()
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg))
+  {
+    ME_RELEASE_IPLIMAGE(cvImg);
+  }
+}
+
+
+void MEImage::Clear()
+{
+  cvSetZero(ME_CAST_TO_IPLIMAGE(cvImg));
+}
+
+
+void MEImage::GetLayer(MEImage& new_layer, int layer_number) const
+{
+  int LayerNumber = layer_number;
+
+  if ((new_layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width) ||
+      (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) ||
+      (new_layer.GetLayers() != 1))
+  {
+    new_layer.Realloc(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height, 1);
+  }
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber)
+  {
+    printf("The given layer number is too large (%d > %d)\n",
+               LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+    LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+  }
+  if (LayerNumber <= 0)
+  {
+    printf("The given layer number is too small (%d <= 0)\n", LayerNumber);
+    LayerNumber = 1;
+  }
+
+  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber);
+  cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), (IplImage*)new_layer.GetIplImage(), NULL);
+  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0);
+}
+
+
+void MEImage::SetLayer(MEImage& layer, int layer_number)
+{
+  int LayerNumber = layer_number;
+
+  if (layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height)
+  {
+    printf("The dimensions of the layer and "
+               "destination image is different (%dx%d <> %dx%d)\n",
+               layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height);
+    return;
+  }
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber)
+  {
+    printf("The given layer number is too large (%d > %d)\n",
+               LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+    LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+  }
+  if (LayerNumber <= 0)
+  {
+    printf("The given layer number is too small (%d <= 0)\n", LayerNumber);
+    LayerNumber = 1;
+  }
+  if (layer.GetLayers() != 1)
+  {
+    printf("The layer image has not one color channel (1 != %d)\n",
+               layer.GetLayers());
+    return;
+  }
+  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber);
+  cvCopy((IplImage*)layer.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg), NULL);
+  cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), 0);
+}
+
+
+void MEImage::CopyImageData(unsigned char* data)
+{
+  memcpy(ME_CAST_TO_IPLIMAGE(cvImg)->imageData, data, ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+}
+
+
+void* MEImage::GetIplImage() const
+{
+  return (void*)ME_CAST_TO_IPLIMAGE(cvImg);
+}
+
+
+void MEImage::SetIplImage(void* image)
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg))
+  {
+    ME_RELEASE_IPLIMAGE(cvImg);
+  }
+  cvImg = cvCloneImage((IplImage*)image);
+  // Correct the origin of the image
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->origin == 1)
+  {
+    MirrorVertical();
+    ME_CAST_TO_IPLIMAGE(cvImg)->origin = 0;
+  }
+}
+
+
+bool MEImage::operator==(const MEImage& image)
+{
+  return Equal(image);
+}
+
+
+bool MEImage::operator!=(const MEImage& image)
+{
+  return !operator==(image);
+}
+
+
+MEImage& MEImage::operator=(const MEImage& other_image)
+{
+  if (&other_image == this)
+    return *this;
+
+  _Copy(other_image);
+  return *this;
+}
+
+
+int MEImage::GetWidth() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : 0;
+}
+
+
+int MEImage::GetRowWidth() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->widthStep : 0;
+}
+
+
+int MEImage::GetHeight() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : 0;
+}
+
+
+int MEImage::GetLayers() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? ME_CAST_TO_IPLIMAGE(cvImg)->nChannels : 0;
+}
+
+
+int MEImage::GetPixelDataNumber() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? GetWidth()*GetHeight()*GetLayers() : 0;
+}
+
+
+unsigned char* MEImage::GetImageData() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData : NULL;
+}
+
+
+void MEImage::SetData(unsigned char* image_data, int width, int height, int channels)
+{
+  _Init(width, height, channels);
+
+  for (int y = height-1; y >= 0; --y)
+  {
+    int Start = GetRowWidth()*y;
+    int Start2 = width*channels*y;
+
+    memcpy(&ME_CAST_TO_IPLIMAGE(cvImg)->imageData[Start], &image_data[Start2], width*channels);
+  }
+}
+
+
+float MEImage::GetRatio() const
+{
+  return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height/(float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0;
+}
+
+
+void MEImage::Realloc(int width, int height)
+{
+  Realloc(width, height, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+}
+
+
+void MEImage::Realloc(int width, int height, int layers)
+{
+  _Init(width, height, layers);
+}
+
+
+void MEImage::Resize(int new_width, int new_height)
+{
+  if (new_height < 1)
+  {
+    printf("Invalid new height: %d < 1\n", new_height);
+    return;
+  }
+  if (new_width < 1)
+  {
+    printf("Invalid new width: %d < 1\n", new_width);
+    return;
+  }
+  IplImage* TempImg = cvCreateImage(cvSize(new_width, new_height), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+  cvResize(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_INTER_NN);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::ResizeScaleX(int new_width)
+{
+  if (new_width < 1)
+  {
+    printf("Invalid new width: %d < 1\n", new_width);
+    return;
+  }
+  Resize(new_width, (int)((float)new_width*GetRatio()));
+}
+
+
+void MEImage::ResizeScaleY(int new_height)
+{
+  if (new_height < 1)
+  {
+    printf("Invalid new height: %d < 1\n", new_height);
+    return;
+  }
+  Resize((int)((float)new_height*1/GetRatio()), new_height);
+}
+
+
+void MEImage::MirrorHorizontal()
+{
+  cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 1);
+}
+
+
+void MEImage::MirrorVertical()
+{
+  cvFlip(ME_CAST_TO_IPLIMAGE(cvImg), NULL, 0);
+}
+
+
+void MEImage::Crop(int x1, int y1, int x2, int y2)
+{
+  int NewX1 = x1;
+  int NewY1 = y1;
+  int NewX2 = x2;
+  int NewY2 = y2;
+
+  NewX1 = (NewX1 < 0) ? 0 : NewX1;
+  NewX1 = (NewX1 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX1;
+  NewY1 = (NewY1 < 0) ? 0 : NewY1;
+  NewY1 = (NewY1 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY1;
+
+  NewX2 = (NewX2 < 0) ? 0 : NewX2;
+  NewX2 = (NewX2 > ME_CAST_TO_IPLIMAGE(cvImg)->width) ? ME_CAST_TO_IPLIMAGE(cvImg)->width : NewX2;
+  NewY2 = (NewY2 < 0) ? 0 : NewY2;
+  NewY2 = (NewY2 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY2;
+
+  if ((NewX2-NewX1) <= 0)
+  {
+    printf("Invalid new width: %d <= 0\n", NewX2-NewX1);
+    return;
+  }
+  if ((NewY2-NewY1) <= 0)
+  {
+    printf("Invalid new height: %d <= 0\n", NewY2-NewY1);
+    return;
+  }
+  IplImage* TempImg = cvCreateImage(cvSize(NewX2-NewX1, NewY2-NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+  cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2-NewX1, NewY2-NewY1));
+  cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), TempImg);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::CopyImageInside(int x, int y, MEImage& source_image)
+{
+  int NewX = x;
+  int NewY = y;
+  int PasteLengthX = source_image.GetWidth();
+  int PasteLengthY = source_image.GetHeight();
+
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != source_image.GetLayers())
+  {
+    if (source_image.GetLayers() == 1 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3)
+    {
+      source_image.ConvertGrayscaleToRGB();
+    }
+    if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1 && source_image.GetLayers() == 3)
+    {
+      source_image.ConvertToGrayscale(g_OpenCV);
+    }
+  }
+  if (NewX < 0)
+    NewX = 0;
+  if (NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width)
+    NewX = ME_CAST_TO_IPLIMAGE(cvImg)->width;
+  if (NewY < 0)
+    NewY = 0;
+  if (NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height)
+    NewY = ME_CAST_TO_IPLIMAGE(cvImg)->height;
+  if (NewX+PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width)
+    PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width-NewX;
+  if (NewY+PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height)
+    PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height-NewY;
+
+  if (PasteLengthX != source_image.GetWidth() ||
+      PasteLengthY != source_image.GetHeight())
+  {
+    source_image.Resize(PasteLengthX, PasteLengthY);
+  }
+  cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX, NewY, PasteLengthX, PasteLengthY));
+  cvCopy((IplImage*)source_image.GetIplImage(), ME_CAST_TO_IPLIMAGE(cvImg));
+  cvResetImageROI(ME_CAST_TO_IPLIMAGE(cvImg));
+}
+
+
+void MEImage::Erode(int iterations)
+{
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                           ME_CAST_TO_IPLIMAGE(cvImg)->height),
+                                    8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+  cvErode(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::Dilate(int iterations)
+{
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                           ME_CAST_TO_IPLIMAGE(cvImg)->height),
+                                    8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+  cvDilate(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::Smooth()
+{
+  SmoothAdvanced(s_Median, 3);
+}
+
+
+void MEImage::SmoothAdvanced(SmoothType filtermode, int filtersize)
+{
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                                    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+  switch (filtermode)
+  {
+    case s_Blur:
+      cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0);
+      break;
+    case s_Median:
+      cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0);
+      break;
+    case s_Gaussian:
+      cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0);
+      break;
+    default:
+      cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0);
+      break;
+  }
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::Canny()
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+  {
+    ConvertToGrayscale(g_OpenCV);
+  }
+
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                                    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+  cvCanny(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 800, 1100, 5);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::Laplace()
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
+  {
+    ConvertToGrayscale(g_OpenCV);
+  }
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                           ME_CAST_TO_IPLIMAGE(cvImg)->height),
+                                    IPL_DEPTH_16S, 1);
+  cvLaplace(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 3);
+  cvConvertScale(TempImg, ME_CAST_TO_IPLIMAGE(cvImg), 1, 0);
+  ME_RELEASE_IPLIMAGE(cvImg);
+}
+
+
+void MEImage::Quantize(int levels)
+{
+  if (levels <= 0)
+  {
+    printf("Level number is too small (%d <= 0)\n", levels);
+    return;
+  }
+  if (levels > 256)
+  {
+    printf("Level number is too large (%d > 256)\n", levels);
+    return;
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+
+  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; --i)
+  {
+    ImageData[i] = ImageData[i] / (256 / levels)*(256 / levels);
+  }
+}
+
+
+void MEImage::Threshold(int threshold_limit)
+{
+  if (threshold_limit < 0)
+  {
+    printf("Threshold number is too small (%d <= 0)\n", threshold_limit);
+    return;
+  }
+  if (threshold_limit > 255)
+  {
+    printf("Threshold number is too large (%d > 255)\n", threshold_limit);
+    return;
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+
+  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; --i)
+  {
+    if (ImageData[i] < threshold_limit)
+    {
+      ImageData[i] = 0;
+    }
+  }
+}
+
+
+void MEImage::AdaptiveThreshold()
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
+  {
+    ConvertToGrayscale(g_OpenCV);
+  }
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                                    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+  cvAdaptiveThreshold(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 25,
+                      CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::ThresholdByMask(MEImage& mask_image)
+{
+  if (mask_image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height)
+  {
+    printf("Image properties are different\n");
+    return;
+  }
+  if (mask_image.GetLayers() != 3 && ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 3)
+  {
+    mask_image.ConvertGrayscaleToRGB();
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* MaskImageData = mask_image.GetImageData();
+
+  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; --i)
+  {
+    if (MaskImageData[i] == 0)
+    {
+      ImageData[i] = 0;
+    }
+  }
+}
+
+
+void MEImage::ColorSpace(ColorSpaceConvertType mode)
+{
+  IplImage* TempImg = NULL;
+  unsigned char* ImageData = NULL;
+  int WidthStep = 0;
+  int RowStart = 0;
+
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1)
+  {
+    printf("No sense to convert: source image is greyscale\n");
+    ConvertGrayscaleToRGB();
+  }
+  switch (mode)
+  {
+    case csc_RGBtoXYZCIED65:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                     ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_XYZCIED65toRGB:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                     ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_RGBtoHSV:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                     ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_HSVtoRGB:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width,
+                                     ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_RGBtoHLS:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_HLStoRGB:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_RGBtoCIELab:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_CIELabtoRGB:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_RGBtoCIELuv:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_CIELuvtoRGB:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                              ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case csc_RGBtoYUV:
+      ComputeColorSpace(csc_RGBtoYUV);
+      break;
+
+    case csc_RGBtoYIQ:
+      ComputeColorSpace(csc_RGBtoYIQ);
+      break;
+
+    case csc_RGBtorgI:
+      ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+      WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+      RowStart = 0;
+      for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+      {
+        for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width-1)*3; x >= 0; x -= 3)
+        {
+          int r = 0;
+          int g = 0;
+          int I = 0;
+
+          I = (int)ImageData[RowStart+x]+(int)ImageData[RowStart+x+1]+(int)ImageData[RowStart+x+2];
+          r = (int)((float)ImageData[RowStart+x] / I*255);
+          g = (int)((float)ImageData[RowStart+x+1] / I*255);
+          ImageData[RowStart+x] = (unsigned char)r;
+          ImageData[RowStart+x+1] = (unsigned char)g;
+          ImageData[RowStart+x+2] = (unsigned char)(I / 3);
+        }
+        RowStart += WidthStep;
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MEImage::ConvertToGrayscale(GrayscaleType grayscale_mode)
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels == 1)
+  {
+    printf("Image is already grayscale\n");
+    return;
+  }
+  IplImage* TempImg = NULL;
+  unsigned char* ImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* ImageData = NULL;
+
+  switch (grayscale_mode)
+  {
+    case g_Average:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
+      ImageData = (unsigned char*)TempImg->imageData;
+
+      for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-3; i >= 0; i -= 3)
+      {
+        ImageData[i / 3] = (ImgData[i]+ImgData[i+1]+ImgData[i+2]) / 3;
+      }
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    case g_OpenCV:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
+      cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY);
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MEImage::ConvertGrayscaleToRGB()
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 1)
+  {
+    return;
+  }
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 3);
+
+  cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GRAY2RGB);
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::ConvertBGRToRGB()
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3)
+  {
+    return;
+  }
+  cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), ME_CAST_TO_IPLIMAGE(cvImg), CV_RGB2BGR);
+}
+
+
+void MEImage::LBP(LBPType mode)
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+  {
+    ConvertToGrayscale(g_OpenCV);
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1);
+  unsigned char* TempImgData = (unsigned char*)TempImg->imageData;
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*2;
+
+  cvSetZero(TempImg);
+  switch (mode)
+  {
+    case lbp_Normal:
+      for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height-2)-1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep+1; --i)
+      {
+        TempImgData[i] =
+            (ImageData[i] <= ImageData[i-ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1])+
+            ((ImageData[i] <= ImageData[i-ME_CAST_TO_IPLIMAGE(cvImg)->widthStep])*2)+
+            ((ImageData[i] <= ImageData[i-ME_CAST_TO_IPLIMAGE(cvImg)->widthStep+1])*4)+
+            ((ImageData[i] <= ImageData[i-1])*8)+
+            ((ImageData[i] <= ImageData[i+1])*16)+
+            ((ImageData[i] <= ImageData[i+ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1])*32)+
+            ((ImageData[i] <= ImageData[i+ME_CAST_TO_IPLIMAGE(cvImg)->widthStep])*64)+
+            ((ImageData[i] <= ImageData[i+ME_CAST_TO_IPLIMAGE(cvImg)->widthStep+1])*128);
+      }
+      break;
+
+    case lbp_Special:
+      for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height-3)-2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*2+2; --i)
+      {
+        int CenterPixel = (ImageData[i+1]+ImageData[i-1]+
+                           ImageData[i-WidthStep]+ImageData[i+WidthStep]) / 4;
+        TempImgData[i] = ((CenterPixel <= (ImageData[i-(WidthStep_2)-2]+
+                           ImageData[i-(WidthStep_2)-1]+
+                           ImageData[i-WidthStep-2]+
+                           ImageData[i-WidthStep-1]) / 4))+
+                         ((CenterPixel <= (ImageData[i-WidthStep]+
+                                            ImageData[i-(WidthStep_2)]) / 2)*2)+
+                         ((CenterPixel <= ((ImageData[i-(WidthStep_2)+2]+
+                           ImageData[i-(WidthStep_2)+1]+
+                           ImageData[i-WidthStep+2]+
+                           ImageData[i-WidthStep+1]) / 4))*4)+
+                         ((CenterPixel <= (ImageData[i-1]+
+                                            ImageData[i-2]) / 2)*8)+
+                         ((CenterPixel <= (ImageData[i+1]+
+                                            ImageData[i+2]) / 2)*16)+
+                         ((CenterPixel <= ((ImageData[i+(WidthStep_2)-2]+
+                           ImageData[i+(WidthStep_2)-1]+
+                           ImageData[i+WidthStep-2]+
+                           ImageData[i+WidthStep-1]) / 4))*32)+
+                         ((CenterPixel <= (ImageData[i+WidthStep]+
+                                            ImageData[i-WidthStep_2]) / 2)*64)+
+                         ((CenterPixel <= ((ImageData[i+(WidthStep_2)+2]+
+                           ImageData[i+(WidthStep_2)+1]+
+                           ImageData[i+WidthStep+2]+
+                           ImageData[i+WidthStep+1]) / 4))*128);
+      }
+      break;
+
+    default:
+      break;
+  }
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+void MEImage::Binarize(int threshold)
+{
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+
+  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i)
+  {
+    if (ImageData[i] >= threshold)
+    {
+      ImageData[i] = 255;
+    } else {
+      ImageData[i] = 0;
+    }
+  }
+}
+
+
+void MEImage::Subtract(MEImage& source, SubtractModeType mode)
+{
+  if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+      source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+  {
+    printf("Image properties are different.\n");
+    return;
+  }
+  unsigned char* ImageData = NULL;
+  unsigned char* DstData = NULL;
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int RowStart = 0;
+
+  switch (mode)
+  {
+    case sub_Normal:
+      ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+      DstData = source.GetImageData();
+      RowStart = 0;
+
+      for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+      {
+        for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+        {
+          ImageData[RowStart+x] =
+            ImageData[RowStart+x]-DstData[RowStart+x] < 0 ? 0 :
+            ImageData[RowStart+x]-DstData[RowStart+x];
+        }
+        RowStart += WidthStep;
+      }
+      break;
+
+    case sub_Absolut:
+      ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+      DstData = source.GetImageData();
+      RowStart = 0;
+
+      for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+      {
+        for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+        {
+          ImageData[RowStart+x] = ImageData[RowStart+x]-
+              DstData[RowStart+x] < 0 ? -ImageData[RowStart+x]+
+              DstData[RowStart+x] : ImageData[RowStart+x]-DstData[RowStart+x];
+        }
+        RowStart += WidthStep;
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MEImage::Multiple(MEImage& source, MultiplicationType mode)
+{
+  if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+      source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+  {
+    printf("Image properties are different.\n");
+    return;
+  }
+  float Result = 0.0;
+  IplImage* TempImg = NULL;
+  unsigned char* ImageData = NULL;
+  unsigned char* ImageData2 = NULL;
+  unsigned char* ImageData3 = NULL;
+  unsigned char* DstData = NULL;
+
+  switch (mode)
+  {
+    case m_Normal:
+      Result = 0;
+      ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+      DstData = source.GetImageData();
+
+      for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i)
+      {
+        if ((ImageData[i] >= 128) && (DstData[i] >= 128))
+        {
+          Result = (float)ImageData[i]/128*(float)DstData[i]/128;
+
+          if (Result >= 1)
+          {
+            ImageData[i] = 255;
+          } else {
+            ImageData[i] = 0;
+          }
+        } else {
+          ImageData[i] = 0;
+        }
+      }
+      break;
+
+    case m_Neighbourhood:
+      TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                                     ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+      ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+      DstData = source.GetImageData();
+      ImageData3 = (unsigned char*)TempImg->imageData;
+
+      for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+        for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width-1; x >= 0; --x)
+          for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; l >= 0; --l)
+      {
+        if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+
+                      x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] == 255) ||
+            (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+
+                        x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] == 255)) &&
+            (NeighbourhoodCounter(x-2, y-2, n_5x5) > 3) &&
+            (source.NeighbourhoodCounter(x-2, y-2, n_5x5) > 3))
+        {
+          ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+
+                     x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] = 255;
+        }
+      }
+      ME_RELEASE_IPLIMAGE(cvImg);
+      cvImg = TempImg;
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MEImage::Addition(MEImage& source, AdditionType mode)
+{
+  if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+      source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+  {
+    printf("Image properties are different.\n");
+    return;
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* DstData = source.GetImageData();
+
+  switch (mode)
+  {
+    case a_Average:
+      for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i)
+      {
+        ImageData[i] = (ImageData[i]+DstData[i]) / 2;
+      }
+      break;
+
+    case a_Union:
+      for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i)
+      {
+        if (DstData[i] > ImageData[i])
+        {
+          ImageData[i] = DstData[i];
+        }
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MEImage::EliminateSinglePixels()
+{
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                                    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* DstData = (unsigned char*)TempImg->imageData;
+  int sum = 0;
+  int xy = 0;
+  int ywidth = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+
+  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width-1; x >= 0; --x)
+  {
+    xy = y*ywidth+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+
+    for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; l >= 0; --l)
+    {
+      if ((ImageData[xy+l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width-1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height-1))
+      {
+        sum = (ImageData[xy-ywidth-ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+
+              (ImageData[xy-ywidth+l] > 0)+
+              (ImageData[xy-ywidth+ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+
+              (ImageData[xy-ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+
+              (ImageData[xy+ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+
+              (ImageData[xy+ywidth-ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+
+              (ImageData[xy+ywidth+l] > 0)+
+              (ImageData[xy+ywidth+ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0);
+
+        if (sum > 3)
+        {
+          DstData[xy+l] = 255;
+        } else {
+          DstData[xy+l] = 0;
+        }
+      } else {
+        DstData[xy+l] = 0;
+      }
+    }
+  }
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
+
+
+float MEImage::DifferenceAreas(MEImage& reference, int difference) const
+{
+  if (reference.GetWidth() != GetWidth() ||
+      reference.GetHeight() != GetHeight() ||
+      reference.GetLayers() != GetLayers())
+  {
+    printf("Image dimensions or channels are different\n");
+    return -1.0;
+  }
+  float PixelDiff = 0.0;
+  int Pixels = 0;
+  unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* RefImgData = reference.GetImageData();
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int RowStart = 0;
+
+  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+  {
+    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+    {
+      if (abs(OrigImgData[RowStart+x]-RefImgData[RowStart+x]) > difference)
+        Pixels++;
+    }
+    RowStart += WidthStep;
+  }
+  PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep)*100;
+  return PixelDiff;
+}
+
+
+int MEImage::AverageDifference(MEImage& reference) const
+{
+  if (reference.GetWidth() != GetWidth() ||
+      reference.GetHeight() != GetHeight() ||
+      reference.GetLayers() != GetLayers())
+  {
+    printf("Image dimensions or channels are different\n");
+    return -1;
+  }
+  int Difference = 0;
+  unsigned char* OrigImgData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* RefImgData = reference.GetImageData();
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int RowStart = 0;
+
+  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+  {
+    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+    {
+      Difference += abs(OrigImgData[RowStart+x]-RefImgData[RowStart+x]);
+    }
+    RowStart += WidthStep;
+  }
+  Difference = Difference / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep);
+  return Difference;
+}
+
+
+void MEImage::Minimum(MEImage& image)
+{
+  if (image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+      image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+  {
+    printf("Image properties are different\n");
+    return;
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* SecData = image.GetImageData();
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int RowStart = 0;
+
+  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+  {
+    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+    {
+      ImageData[RowStart+x] = ImageData[RowStart+x] > SecData[RowStart+x] ?
+                              SecData[RowStart+x] : ImageData[RowStart+x];
+    }
+    RowStart += WidthStep;
+  }
+}
+
+
+float MEImage::AverageBrightnessLevel() const
+{
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int RowStart = 0;
+  int BrightnessLevel = 0;
+
+  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+  {
+    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+    {
+      BrightnessLevel += (int)ImageData[RowStart+x];
+    }
+    RowStart += WidthStep;
+  }
+  return BrightnessLevel / (GetWidth()*GetHeight()*GetLayers());
+}
+
+
+bool MEImage::Equal(const MEImage& reference) const
+{
+  return Equal(reference, 1);
+}
+
+
+bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const
+{
+  bool Ret = true;
+
+  if (reference.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width ||
+      reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height ||
+      reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels)
+  {
+    printf("Image properties are different\n");
+    return false;
+  }
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* RefData = reference.GetImageData();
+  int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep;
+  int RowStart = 0;
+
+  for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y)
+  {
+    for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x)
+    {
+      if (abs(ImageData[RowStart+x]-RefData[RowStart+x]) >= maxabsdiff)
+      {
+        Ret = false;
+        return Ret;
+      }
+    }
+    RowStart += WidthStep;
+  }
+  return Ret;
+}
+
+
+unsigned char MEImage::GrayscalePixel(int x, int y) const
+{
+  int NewX = x;
+  int NewY = y;
+
+  NewX = NewX < 0 ? 0 : NewX;
+  NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width-1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width-1 : NewX;
+  NewY = NewY < 0 ? 0 : NewY;
+  NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height-1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height-1 : NewY;
+
+  float Sum = 0;
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+
+  for (int l = 0; l < ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; l++)
+  {
+    Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l];
+  }
+  Sum = Sum / ME_CAST_TO_IPLIMAGE(cvImg)->nChannels;
+  return (unsigned char)(Sum);
+}
+
+
+int MEImage::NeighbourhoodCounter(int startx, int starty,
+                                  NeighbourhoodType neighbourhood) const
+{
+  int IterX = 0;
+  int IterY = 0;
+  int Counter = 0;
+
+  // Determine the iteration numbers
+  switch (neighbourhood)
+  {
+    case n_2x2:
+      IterX = 2;
+      IterY = 2;
+      break;
+
+    case n_3x3:
+      IterX = 3;
+      IterY = 3;
+      break;
+
+    case n_3x2:
+      IterX = 2;
+      IterY = 3;
+      break;
+
+    case n_5x5:
+      IterX = 5;
+      IterY = 5;
+      break;
+
+    case n_7x7:
+      IterX = 7;
+      IterY = 7;
+      break;
+
+    default:
+      IterX = 3;
+      IterY = 3;
+      break;
+  }
+
+  int NewStartX = startx ;
+  int NewStartY = starty;
+
+  NewStartX = startx < 0 ? 0 : startx;
+  NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width-IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width-IterX-1 : startx;
+  NewStartY = starty < 0 ? 0 : starty;
+  NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height-IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height-IterY-1 : starty;
+
+  int Value = 0;
+  unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+
+  for (int x = NewStartX; x < NewStartX+IterX; x++)
+    for (int y = NewStartY; y < NewStartY+IterY; y++)
+  {
+    Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels]+
+             (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+1]+
+             (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+2]) / 3;
+
+    if (Value == 255)
+    {
+      Counter++;
+    }
+  }
+  return Counter;
+}
+
+
+void MEImage::GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y)
+{
+  int Results[8];
+  int DiagonalMaskSize = (int)((float)mask_size / sqrt(2));
+
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+  {
+    ConvertToGrayscale(g_OpenCV);
+  }
+  if (smooth)
+  {
+    SmoothAdvanced(s_Gaussian, mask_size*3-(mask_size*3-1) % 2);
+  }
+
+  Results[0] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x,y-mask_size);
+  Results[1] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+DiagonalMaskSize,y-DiagonalMaskSize);
+  Results[2] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+mask_size,y);
+  Results[3] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+DiagonalMaskSize,y+DiagonalMaskSize);
+  Results[4] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x,y+mask_size);
+  Results[5] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x-DiagonalMaskSize,y+DiagonalMaskSize);
+  Results[6] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x-mask_size,y);
+  Results[7] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+DiagonalMaskSize,y-DiagonalMaskSize);
+
+  result_x = (DiagonalMaskSize*Results[1]+mask_size*Results[2]+
+             DiagonalMaskSize*Results[3]-DiagonalMaskSize*Results[5]-
+             mask_size*Results[6]+DiagonalMaskSize*Results[7]) / 256;
+  result_y = (-mask_size*Results[0]-DiagonalMaskSize*Results[1]+
+             DiagonalMaskSize*Results[3]+mask_size*Results[4]+
+             DiagonalMaskSize*Results[5]-DiagonalMaskSize*Results[7]) / 256;
+}
+
+
+void MEImage::GradientVisualize(int vector_x, int vector_y)
+{
+  if (vector_x <= 0)
+  {
+    printf("vectorx: wrong parameter (%d <= 0)\n", vector_x);
+    return;
+  }
+  if (vector_y <= 0)
+  {
+    printf("vectory: wrong parameter (%d <= 0)\n", vector_y);
+    return;
+  }
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels > 1)
+  {
+    ConvertToGrayscale(g_OpenCV);
+  }
+
+  int masksize = (ME_CAST_TO_IPLIMAGE(cvImg)->width < ME_CAST_TO_IPLIMAGE(cvImg)->height) ?
+                 ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x+1) :
+                 ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y+1);
+
+  SmoothAdvanced(s_Gaussian, masksize*2-1);
+  for (int i = 1; i < vector_x; i++)
+    for (int i1 = 1; i1 < vector_y; i1++)
+  {
+    int Resultx = 0, Resulty = 0;
+    int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x)));
+    int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y)));
+
+    GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty);
+
+    CvPoint Point1;
+    CvPoint Point2;
+
+    Point1.x = x-Resultx / 2;
+    Point1.y = y-Resulty / 2;
+    Point2.x = x+Resultx / 2;
+    Point2.y = y+Resulty / 2;
+    cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB(255, 255, 255), 1, 8);
+  }
+}
+
+
+bool MEImage::_Copy(const MEImage& other_image)
+{
+  if (&other_image == this)
+    return true;
+
+  if (ME_CAST_TO_IPLIMAGE(cvImg))
+  {
+    ME_RELEASE_IPLIMAGE(cvImg);
+  }
+  cvImg = cvCloneImage((IplImage*)other_image.GetIplImage());
+  return true;
+}
+
+
+void MEImage::_Init(int width, int height, int layers)
+{
+  if (width < 1)
+  {
+    printf("Given width for the new image is too small (%d <= 0)\n", width);
+    return;
+  }
+  if (height < 1)
+  {
+    printf("Given height for the new image is (%d <= 0)\n", height);
+    return;
+  }
+  if ((layers != 1) && (layers != 3))
+  {
+    printf("Only one or three (%d != 1 or 3) layer allowed\n", layers);
+    return;
+  }
+
+  if (ME_CAST_TO_IPLIMAGE(cvImg))
+  {
+    ME_RELEASE_IPLIMAGE(cvImg);
+  }
+  cvImg = cvCreateImage(cvSize(width, height), 8, layers);
+}
+
+
+void MEImage::ComputeColorSpace(ColorSpaceConvertType mode)
+{
+  if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels != 3)
+  {
+    printf("Image has to have three color channels (%d != 3)\n", ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+    return;
+  }
+  IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8,
+                                    ME_CAST_TO_IPLIMAGE(cvImg)->nChannels);
+
+  for (int i = 0; i < 3; i++)
+    for (int i1 = 0; i1 < 3; i1++)
+  {
+    if (mode == csc_RGBtoYUV)
+      TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1];
+    if (mode == csc_RGBtoYIQ)
+      TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1];
+  }
+  float x = 0.0;
+  float y = 0.0;
+  float z = 0.0;
+  float xmin = 0.0;
+  float xmax = 0.0;
+  float ymin = 0.0;
+  float ymax = 0.0;
+  float zmin = 0.0;
+  float zmax = 0.0;
+
+  if (mode == csc_RGBtoYUV)
+  {
+    xmin = 0.0;
+    xmax = 255.0;
+    ymin = -111.18;
+    ymax = 111.18;
+    zmin = -156.825;
+    zmax = 156.825;
+  }
+  if (mode == csc_RGBtoYIQ)
+  {
+    xmin = 0.0;
+    xmax = 255.0;
+    ymin = -151.98;
+    ymax = 151.98;
+    zmin = -133.365;
+    zmax = 133.365;
+  }
+  unsigned char* SrcData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData;
+  unsigned char* DstData = (unsigned char*)TempImg->imageData;
+
+  for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; i-=3)
+  {
+    x = (float)SrcData[i]*TransformMatrix[0][0]+
+        (float)SrcData[i+1]*TransformMatrix[0][1]+
+        (float)SrcData[i+2]*TransformMatrix[0][2];
+    y = (float)SrcData[i]*TransformMatrix[1][0]+
+        (float)SrcData[i+1]*TransformMatrix[1][1]+
+        (float)SrcData[i+2]*TransformMatrix[1][2];
+    z = (float)SrcData[i]*TransformMatrix[2][0]+
+        (float)SrcData[i+1]*TransformMatrix[2][1]+
+        (float)SrcData[i+2]*TransformMatrix[2][2];
+
+    x = xmax-xmin != 0.0 ? 255.0 : (x-xmin) / (xmax-xmin)*255.0;
+    y = ymax-ymin != 0.0 ? 255.0 : (y-xmin) / (ymax-ymin)*255.0;
+    z = zmax-zmin != 0.0 ? 255.0 : (z-xmin) / (zmax-zmin)*255.0;
+
+    DstData[i] = (unsigned char)MEBound(0, (int)x, 255);
+    DstData[i+1] = (unsigned char)MEBound(0, (int)y, 255);
+    DstData[i+2] = (unsigned char)MEBound(0, (int)z, 255);
+  }
+  ME_RELEASE_IPLIMAGE(cvImg);
+  cvImg = TempImg;
+}
diff --git a/package_bgs/ck/MEImage.hpp b/package_bgs/ck/MEImage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..41ada3ba71e086fd1b6ef0d1517f7ff34261f7bb
--- /dev/null
+++ b/package_bgs/ck/MEImage.hpp
@@ -0,0 +1,999 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef MEImage_H
+#define MEImage_H
+
+/**
+ *  @addtogroup mindeye
+ *  @{
+ */
+
+/**
+ * MEImage
+ * @brief Basic image functions
+ */
+class MEImage
+{
+public:
+  /// Types of LBP operator
+  typedef enum {
+    lbp_Min = 0,          /*!< Minimum value */
+    lbp_Normal = lbp_Min, /*!< Normal LBP pattern */
+    lbp_Special,          /*!< Special LBP pattern */
+    lbp_Max = lbp_Special /*!< Maximum value */
+  } LBPType;
+
+  /// Types of image subtraction
+  typedef enum {
+    sub_Min = 0,          /*!< Minimum value */
+    sub_Normal = sub_Min, /*!< Normal */
+    sub_Absolut,          /*!< Absolut */
+    sub_Max = sub_Absolut /*!< Maximum value */
+  } SubtractModeType;
+
+  /// Types of image addition
+  typedef enum {
+    a_Min = 0,         /*!< Minimum value */
+    a_Average = a_Min, /*!< Average */
+    a_Union,           /*!< Union */
+    a_Max = a_Union    /*!< Maximum value */
+  } AdditionType;
+
+  /// Types of image multiplication
+  typedef enum {
+    m_Min = 0,              /*!< Minimum value */
+    m_Normal = m_Min,       /*!< Normal */
+    m_Neighbourhood,        /*!< Neighbourhood */
+    m_Max = m_Neighbourhood /*!< Maximum value */
+  } MultiplicationType;
+
+  /// Types of grayscale conversation
+  typedef enum {
+    g_Min = 0,         /*!< Minimum value */
+    g_Average = g_Min, /*!< Average */
+    g_OpenCV,          /*!< OpenCV */
+    g_Max = g_OpenCV   /*!< Maximum value */
+  } GrayscaleType;
+
+  /// Types of pixel neighbourhoods
+  typedef enum {
+    n_Min = 0,     /*!< Minimum value */
+    n_2x2 = n_Min, /*!< 2x2 */
+    n_3x2,         /*!< 3x2 */
+    n_3x3,         /*!< 3x3 */
+    n_5x5,         /*!< 5x5 */
+    n_7x7,         /*!< 7x7 */
+    n_Max = n_7x7  /*!< Maximum value */
+  } NeighbourhoodType;
+
+  /// Types of special pixels
+  typedef enum {
+    p_Min = 0,         /*!< Minimum value */
+    p_Minimum = p_Min, /*!< Minimum */
+    p_Maximum,         /*!< Maximum */
+    p_Counter,         /*!< Counter */
+    p_Max = p_Counter  /*!< Maximum value */
+  } PixelType;
+
+  /// Types of smooth operation
+  typedef enum {
+    s_Min = 0,       /*!< Minimum value */
+    s_Blur = s_Min,  /*!< Blur */
+    s_Gaussian,      /*!< Gaussian */
+    s_Median,        /*!< Medium */
+    s_Max = s_Median /*!< Maximum value */
+  } SmoothType;
+
+  /// Types of color space conversions
+  typedef enum {
+    csc_Min = 0,                  /*!< Minimum value */
+    csc_RGBtoXYZCIED65 = csc_Min, /*!< RGB to XYZCIED65 */
+    csc_XYZCIED65toRGB,           /*!< XYZCIED65 to RGB */
+    csc_RGBtoHSV,                 /*!< RGB to HSV */
+    csc_HSVtoRGB,                 /*!< HSV to RGB */
+    csc_RGBtoHLS,                 /*!< RGB to HLS */
+    csc_HLStoRGB,                 /*!< HLS to RGB */
+    csc_RGBtoCIELab,              /*!< RGB to CIELab */
+    csc_CIELabtoRGB,              /*!< CIELab to RGB */
+    csc_RGBtoCIELuv,              /*!< RGB to CIELuv */
+    csc_CIELuvtoRGB,              /*!< CIELuv to RGB */
+    csc_RGBtoYUV,                 /*!< RGB to YUV */
+    csc_RGBtoYIQ,                 /*!< RGB to YIQ */
+    csc_RGBtorgI,                 /*!< RGB to rgI */
+    csc_Max = csc_RGBtorgI        /*!< Maximum value */
+  } ColorSpaceConvertType;
+
+  /*!
+   * @brief Class constructor
+   *
+   * @param width Image width
+   * @param height Image height
+   * @param layers Layers
+   *
+   * Class constructor with the possibility to specify the image width,
+   * height and the layers. The default options are 16x16x1.
+   *
+   */
+
+  MEImage(int width = 16, int height = 16, int layers = 1);
+
+  /*!
+   * @brief Class constructor
+   *
+   * @param other Other image
+   *
+   * Class constructor with the possibility to specify the image width,
+   * height and the layers. The default options are 16x16x1.
+   *
+   */
+
+  MEImage(const MEImage& other);
+  /// Destructor of class
+  ~MEImage();
+
+  /*
+  -------------------------------------------------------------------
+                          Basic functions
+  -------------------------------------------------------------------
+  */
+
+  /*!
+   * @brief Clear image
+   *
+   * This function clears image by filling all image data with zero
+   * value.
+   *
+   */
+
+  void Clear();
+
+  /*!
+   * @brief Get an color layer of image
+   *
+   * @param new_layer new image of layer
+   * @param layernumber number of layer which will be copied
+   *
+   * Copy an image layer (R, G or B) to @a new_layer image. @a new_layer has to
+   * have only one color layer (greyscale). If @a new_layer is not
+   * greyscale or it has got different width or height like source image
+   * than function reallocates it with appropriate features before
+   * copying image data.
+   *
+   */
+
+  void GetLayer(MEImage& new_layer, int layernumber) const;
+
+  /*!
+   * @brief Copy a new color layer to image
+   *
+   * @param new_layer image data of new color layer
+   * @param layernumber number of layer where image data will copy
+   *
+   * Copy a new image layer from @a new_layer image. @a new_layer has to
+   * have only one color layer (greyscale). If @a new_layer is not
+   * greyscale or it has got different width or height like source image
+   * than function halts with an error message.
+   *
+   */
+
+  void SetLayer(MEImage& new_layer, int layernumber);
+
+  /*!
+   * @brief Copy image data to a pointer
+   *
+   * @param data pointer where image data will be copied
+   *
+   * Function in order to acquire image data to an external
+   * (unsigned char*) pointer.
+   *
+   */
+
+  void CopyImageData(unsigned char* data);
+
+  /*!
+   * @brief Get a pointer to the internal IplImage
+   *
+   * @return Pointer to the IplImage
+   *
+   * This function returns the internal IplImage of the class. The
+   * image data can not be modified.
+   *
+   */
+
+  void* GetIplImage() const;
+
+  /*!
+   * @brief Set the internal IplImage
+   *
+   * @param image Pointer to the IplImage
+   *
+   * This function sets the internal IplImage of the class.
+   *
+   */
+
+  void SetIplImage(void* image);
+
+  /*!
+   * @brief Handle operator == for MEImage
+   *
+   * @param image image to check
+   *
+   * @return true if the images are equal otherwise false.
+   *
+   * The operator checks the equality of two images.
+   *
+   */
+
+  bool operator==(const MEImage& image);
+
+  /*!
+   * @brief Handle operator != for MEImage
+   *
+   * @param image image to check
+   *
+   * @return true if the images are not equal otherwise false.
+   *
+   * The operator checks the non-equality of two images.
+   *
+   */
+
+  bool operator!=(const MEImage& image);
+
+  /*!
+   * @brief Handle operator = for MEImage
+   *
+   * @param other_image image to copy operation
+   *
+   * @return Reference to the actual instance.
+   *
+   * Copy image data to @a other_image image. Function calls only
+   * _Copy() directly.
+   *
+   */
+
+  MEImage& operator=(const MEImage& other_image);
+
+  /*!
+   * @brief Get the width of the image
+   *
+   * @return Width of the image
+   *
+   * Get the width of the image.
+   *
+   */
+
+  int GetWidth() const;
+
+  /*!
+   * @brief Get the height of the image
+   *
+   * @return Height of the image
+   *
+   * Get the height of the image.
+   */
+
+  int GetHeight() const;
+
+  /*!
+   * @brief Get the length of a pixel row of the image
+   *
+   * @return Length of a pixel row
+   *
+   * Get the row width of the image.
+   *
+   */
+
+  int GetRowWidth() const;
+
+  /*!
+   * @brief Get the number of color layers of the image
+   *
+   * @return Number of color layer of the image
+   *
+   * Get the number of color layer of the image.
+   *
+   */
+
+  int GetLayers() const;
+
+  /*!
+   * @brief Get the number of the image pixel data
+   *
+   * @return Number of the image pixel data
+   *
+   * Get the number of the image pixel data.
+   *
+   */
+
+  int GetPixelDataNumber() const;
+
+  /*!
+   * @brief Get the image data
+   *
+   * @return Pointer to the image data
+   *
+   * Get a pointer to the image.
+   *
+   */
+
+  unsigned char* GetImageData() const;
+
+  /*!
+   * @brief Set the image data
+   *
+   * @param image_data New image data
+   * @param width New image width
+   * @param height New image height
+   * @param channels New image color channels
+   *
+   * Get a pointer to the image.
+   *
+   */
+
+  void SetData(unsigned char* image_data, int width, int height, int channels);
+
+  /*!
+   * @brief Get ratio of image width and height
+   *
+   * @return float ratio of image dimensions
+   *
+   * Function calculates ratio of image width and height with
+   * following equation: ratio = height / width.
+   */
+
+  float GetRatio() const;
+
+  /*
+  -------------------------------------------------------------------
+                       Basic image manipulation
+  -------------------------------------------------------------------
+  */
+
+  /*!
+   * @brief Reallocate image data
+   *
+   * @param width New width of the image
+   * @param height New height of the image
+   *
+   * Image data will be reallocated with new dimensions @a width
+   * and @a height. Number of color channels is not changed.
+   *
+   */
+
+  void Realloc(int width, int height);
+
+  /*!
+   * @brief Reallocate image data
+   *
+   * @param width New width of the image
+   * @param height New height of the image
+   * @param layers Number of color channels of the image
+   *
+   * Image data will be reallocated with new dimensions @a width,
+   * @a height and new number of color channels @a layers.
+   *
+   */
+
+  void Realloc(int width, int height, int layers);
+
+  /*!
+   * @brief Resize image
+   *
+   * @param newwidth new width of image
+   * @param newheight new height of image
+   *
+   * Resize image to @a newwidth width and @a newheight
+   * height dimensions.
+   *
+   */
+
+  void Resize(int newwidth, int newheight);
+
+  /*!
+   * @brief Resize image with new width
+   *
+   * @param newwidth new width of image
+   *
+   * Image is resized with only new width information therefore
+   * fit to original ratio.
+   *
+   */
+
+  void ResizeScaleX(int newwidth);
+
+  /*!
+   * @brief Resize image with new height
+   *
+   * @param newheight new height of image
+   *
+   * Image is resized with only new height information therefore
+   * fit to original ratio.
+   *
+   */
+
+  void ResizeScaleY(int newheight);
+
+  /*!
+   * @brief Reverse image in horizontal direction
+   *
+   * Function makes a mirror transformation on image in horizontal
+   * direction.
+   *
+   */
+
+  void MirrorHorizontal();
+
+  /*!
+   * @brief Reverse image in vertical direction
+   *
+   * Function makes a mirror transformation on image in vertical
+   * direction.
+   *
+   */
+
+  void MirrorVertical();
+
+  /*!
+   * @brief Crop image
+   *
+   * @param x1, y1 coordinates of top-left point of rectangle
+   * @param x2, y2 coordinates of bottom-right point of rectangle
+   *
+   * Crop the image in a smaller piece whose dimensions are
+   * specified as a rectangle. Top-left and bottom-right
+   * coordinates of rectangle are (x1, y1) and (x2, y2) wherefrom
+   * comes that the width of the new image is x2-x1 and height is
+   * y2-y1.
+   *
+   */
+
+  void Crop(int x1, int y1, int x2, int y2);
+
+  /*!
+   * @brief Copy all image data from an other picture
+   *
+   * @param x0 x coordinate to paste the new image data
+   * @param y0 y coordinate to paste the new image data
+   * @param source_image source image
+   *
+   * Function copies all image data from @a source_image
+   * to the given coordinate (x0,y0).
+   *
+   */
+
+  void CopyImageInside(int x0, int y0, MEImage& source_image);
+
+  /*
+  -------------------------------------------------------------------
+                     Image processing functions
+  -------------------------------------------------------------------
+  */
+
+  /*!
+   * @brief Erode function
+   *
+   * @param iterations iterations of erode method
+   *
+   * Method makes an erode filter on an image @a iterations
+   * times with standard 3x3 matrix size.
+   *
+   */
+
+  void Erode(int iterations);
+
+  /*!
+   * @brief Dilate function
+   *
+   * @param iterations iterations of dilate method
+   *
+   * Method makes an dilate filter on an image
+   * @a iterations times with standard 3x3 matrix size.
+   *
+   */
+
+  void Dilate(int iterations);
+
+  /*!
+   * @brief Smooth function
+   *
+   * Method smooths with median filter and standard 3x3 matrix size.
+   * (Median filter works fine and fast.)
+   *
+   */
+
+  void Smooth();
+
+  /*!
+   * @brief Smooth function with defined parameters
+   *
+   * @param filtermode type of smooth method
+   * @param filtersize the size of the convolution matrix
+   *
+   * Method smooths with median filter and the given matrix
+   * size (@a filtersize x @a filtersize). There are more
+   * types of smooth function (@a filtermode):
+   *
+   * - s_Blur: Blur filter.
+   * - s_Gaussian: Gaussian filter.
+   * - s_Median: Median filter.
+   *
+   */
+
+  void SmoothAdvanced(SmoothType filtermode, int filtersize);
+
+  /*!
+   * @brief Canny function
+   *
+   * Canny operator is usable for edge detection. Function makes
+   * this operation with standard 3x3 matrix
+   * size. Canny has two threshold value which are set to zero
+   * in this function by default.
+   *
+   */
+
+  void Canny();
+
+  /*!
+   * @brief Laplace function
+   *
+   * Laplace operator is usable for edge detection like Canny.
+   * This function makes a laplace filter with
+   * standard 3x3 matrix size. After calculating destination image will
+   * be converted from 16 bit back to 8 bit.
+   *
+   */
+
+  void Laplace();
+
+  /*!
+   * @brief Image quantisation
+   *
+   * @param levels level of quantisation
+   *
+   * Quantize an image with @a levels level. It means by 16
+   * level color range 0-255 quantizes to 0-15, by 4 level to 0-63 etc.
+   *
+   */
+
+  void Quantize(int levels);
+
+  /*!
+   * @brief Threshold a picture
+   *
+   * @param threshold_limit limit for threshold
+   *
+   * Threshold an image with @a threshold_limit limit. Value range
+   * of @a threshold_limit is between 0-255. E.g. by value 160 functions
+   * will eliminate all color values under 160 with black color
+   * (color value zero).
+   *
+   */
+
+  void Threshold(int threshold_limit);
+
+  /*!
+   * @brief Adaptive threshold function
+   *
+   * This function does adaptive threshold function.
+   *
+   */
+
+  void AdaptiveThreshold();
+
+  /*!
+   * @brief Threshold a picture by a mask image
+   *
+   * @param mask_image mask image for thresholding
+   *
+   * Threshold an image with a mask image @a mask_image.
+   *
+   */
+
+  void ThresholdByMask(MEImage& mask_image);
+
+  /*!
+   * @brief Convert an image into a new color space
+   *
+   * @param transformation Definition of color transformation
+   *
+   * This function converts an image from a specified color space
+   * to an other.
+   * Current supported conversions (@a transformation):
+   * - csc_RGBtoXYZCIED65: RGB to XYZ (D65 reference light),
+   * - csc_XYZCIED65toRGB: XYZ to RGB (D65 reference light),
+   * - csc_RGBtoHSV: RGB to HSV,
+   * - csc_HSVtoRGB: HSV to RGB,
+   * - csc_RGBtoHLS: RGB to HSV,
+   * - csc_HLStoRGB: HSV to RGB,
+   * - csc_RGBtoCIELab: RGB to CIELab,
+   * - csc_CIELabtoRGB: CIELuv to RGB,
+   * - csc_RGBtoCIELuv: RGB to CIELuv,
+   * - csc_CIELuvtoRGB: CIELuv to RGB,
+   * - csc_RGBtoYUV: RGB to YUV color space,
+   * - csc_RGBtoYIQ: RGB to YIQ color space.
+   *
+   */
+
+  void ColorSpace(ColorSpaceConvertType transformation);
+
+  /*!
+   * @brief Convert an image to grayscale
+   *
+   * @param grayscale_mode mode of grayscale conversation
+   *
+   * The function converts the image to grayscale version
+   * (one color channel after the conversion). There is four
+   * different ways to convert the image to grayscale what we
+   * can define with @a grayscale_mode:
+   *
+   *  - g_Average: It computes the average grayscale
+   * values of the pixels with arithmetical average.
+   *  - g_OpenCV: It computes the average grayscale
+   * values by help of the values of the Y channel.
+   *
+   */
+
+  void ConvertToGrayscale(GrayscaleType grayscale_mode = g_OpenCV);
+
+  /*!
+   * @brief Convert a grayscale image to RGB
+   *
+   * The function converts the grayscale image to RGB version.
+   * (It copies the info from a single color channel to
+   * three color channel.)
+   *
+   */
+
+  void ConvertGrayscaleToRGB();
+
+  /*!
+   * @brief Change the red and blue components of every pixels
+   *
+   * Function changes the red component with the blue of
+   * every pixels. (Simple conversion from RGB->BGR.)
+   *
+   */
+
+  void ConvertBGRToRGB();
+
+  /*!
+   * @brief Compute an LBP filter on the image
+   *
+   * @param mode The LBP operator type
+   *
+   * The function converts the image to binary version over the
+   * threshold value.
+   *
+   */
+
+  void LBP(LBPType mode = lbp_Special);
+
+  /*!
+   * @brief Binarize an image
+   *
+   * @param threshold Threshold value
+   *
+   * The function converts the image to binary version over the
+   * threshold value.
+   *
+   */
+
+  void Binarize(int threshold);
+
+  /*!
+   * @brief Subtract an image from the internal picture
+   *
+   * @param source Source image for subtraction
+   * @param mode Calculation mode of difference feature
+   *
+   * Function generates a difference image between two image:
+   * the internal picture of this class and @a source_image.
+   * The calculation mode is determined by @a mode parameter.
+   * Function supports the following modes:
+   *
+   *  - sub_Normal: Simple subtraction between each
+   * correspondent pixel (per color channels). The result values
+   * are converted to absolute value and normalized to
+   * range 0-255.
+   *
+   */
+
+  void Subtract(MEImage& source, SubtractModeType mode);
+
+  /*!
+   * @brief Multiple an image with the internal picture
+   *
+   * @param source Second source image for multiplication
+   * @param mode Multiplication mode
+   *
+   * Function multiples an image with the internal image of this class and
+   * the result is stored in the internal image. The implemented calculation
+   * modes:
+   *
+   *  - m_Normal: It multiples the corresponding pixel values
+   * of the two images. The original pixel values are divided by 128 and
+   * multiplied together. If the result is at least 1 then the new pixel value
+   * is 255 otherwise 0.
+   *  - m_Neighbourhood: It multiples all pixel values of its
+   * 3x3 neighbourhood separately (see the method at MULTIPLICATION_NORMAL)
+   * and the new pixel value is 255 if at least two pixel is active in the
+   * 3x3 neighbourhood otherwise 0.
+   *
+   */
+
+  void Multiple(MEImage& source, MultiplicationType mode);
+
+  /*!
+   * @brief Addition of an image and the internal picture
+   *
+   * @param source second source image for addition method
+   * @param mode the declaration of the used addition mode
+   *
+   * Function makes an addition operation between an image and the internal
+   * image of this class and the result is stored in the internal image.
+   * Supported modes:
+   *
+   *  - a_Average: It sums the average of the corresponding pixels
+   * of each pictures.
+   *  - a_Union: It sums the union of the corresponding pixels
+   * of each pictures.
+   *
+   */
+
+  void Addition(MEImage& source, AdditionType mode);
+
+  /*!
+   * @brief Eliminate the single pixels from a binary image
+   *
+   * Function eliminates such a pixels which do not have neighbour pixels with
+   * 255 value in a 3x3 neighbourhood. The image should be converted to binary
+   * version.
+   *
+   */
+
+  void EliminateSinglePixels();
+
+  /*!
+   * @brief Calculate an area difference feature between two images
+   *
+   * @param reference Reference image
+   * @param difference Difference
+   *
+   * @return The percentage of image areas representing the conditions
+   *
+   * Function calculates a similarity feature between two pictures.
+   * Counts the number of the pixels whose intensity difference is
+   * higher than @a difference. (Range: 0..100)
+   *
+   */
+
+  float DifferenceAreas(MEImage& reference, int difference) const;
+
+  /*!
+   * @brief Calculate an average difference between two images
+   *
+   * @param reference Reference image
+   *
+   * @return Average difference of the pixels
+   *
+   * Function calculates a similarity feature between
+   * two images. It returns a simple sum of the absolute difference
+   * of each pixel in the two images and averaged by the pixel number.
+   * (Range: 0..255)
+   *
+   */
+
+  int AverageDifference(MEImage& reference) const;
+
+  /*!
+   * @brief Calculate minimum of image data
+   *
+   * @param image Second image
+   *
+   * Function calculates the minimum of current and given image.
+   *
+   */
+
+  void Minimum(MEImage& image);
+
+  /*!
+   * @brief Calculate average brightness level
+   *
+   * @return Brightness level in range 0-255.
+   *
+   * Function calculates the average brightness level of the image.
+   *
+   */
+
+  float AverageBrightnessLevel() const;
+
+  /*!
+   * @brief Check the equalization with a reference image
+   *
+   * @param reference Reference image
+   *
+   * @return true in case of binary equalization, otherwise false.
+   *
+   * Function calculates the binary difference between
+   * the image and the reference image.
+   *
+   */
+
+  bool Equal(const MEImage& reference) const;
+
+  /*!
+   * @brief Check the equalization with a reference image
+   *
+   * @param reference Reference image
+   * @param maxabsdiff Maximal absolute difference
+   *
+   * @return true in case of equalization, otherwise false.
+   *
+   * Function checks the difference between the image and
+   * the reference image. Two pixels are equal in a range of
+   * a maximal absolute difference.
+   *
+   */
+
+  bool Equal(const MEImage& reference, int maxabsdiff) const;
+
+  /*!
+   * @brief Get the grayscale value of a pixel
+   *
+   * @param x X coordinate of the pixel
+   * @param y Y coordinate of the pixel
+   *
+   * @return grayscale value of the pixel
+   *
+   * The method gives the grayscale value of a pixel back. If
+   * the image has 3 color channels (e.g. RGB) then Y value of
+   * YIQ/YUV color space will be calculated otherwise normal
+   * averaged grayscale value.
+   *
+   */
+
+  unsigned char GrayscalePixel(int x, int y) const;
+
+  /*!
+   * @brief Count the number of neighbourhood pixels with maximum intensity
+   *
+   * @param startx X coordinate of the top-left pixel
+   * @param starty Y coordinate of the top-left pixel
+   * @param neighbourhood Specific subset of pixels
+   *
+   * @return number of the pixels with maximum intensity.
+   *
+   * The method counts the number of the pixels with maximum
+   * intensity (255) in a specified subset of pixels.
+   * The grayscale values of the pixels are used in the counter
+   * process. The following neighbourhood forms are allowed with
+   * the @a neighbourhood parameter:
+   *
+   *  - n_2X2: Simple 2x2 matrix.
+   *  - n_3X3: Simple 3x3 matrix.
+   *  - n_3x2: Simple 3x2 matrix.
+   *
+   */
+
+  int NeighbourhoodCounter(int startx, int starty, NeighbourhoodType neighbourhood) const;
+
+  /*!
+   * @brief Calculate the gradient vector in a point
+   *
+   * @param smooth compute smooth filter
+   * @param x X coordinate of the point
+   * @param y Y coordinate of the point
+   * @param mask_size The mask size to calculate the gradient
+   *
+   * @param result_x X component of the calculated vector
+   * @param result_y Y component of the calculated vector
+   *
+   * The method calculates the gradient vector in a given point.
+   * The image is preprocessed with a Gauss filter to smooth the
+   * image content. The filter size of the Gauss filter depends on
+   * mask size of the gradient vector: filter size = mask size*3.
+   * Eight points are assigned to the initial point to compute
+   * a vector sum: (x, y-mask_size), (x+mask_size/√2, y-mask_size/√2),
+   * (x+mask_size, y), (x+mask_size/√2, y+mask_size/√2), (x, y+mask_size),
+   * (x-mask_size/√2, y+mask_size/√2), (x-mask_size, y), (x-mask_size/√2, y-mask_size/√2).
+   * The lengths of all vectors equalize with the mask size.
+   * After that each vector is multiplied with the gradient difference between
+   * its two end points. The results are summarized and normalized by
+   * the mask size.
+   *
+   */
+
+  void GradientVector(bool smooth, int x, int y, int mask_size, int& result_x, int& result_y);
+
+  /*!
+   * @brief Visualize gradient vectors
+   *
+   * @param vector_x Number of points horizontally
+   * @param vector_y Number of points vertically
+   *
+   * This function draws a wire (@a vector_x * @a vector_y) with
+   * gradient vectors.
+   *
+   */
+
+  void GradientVisualize(int vector_x, int vector_y);
+
+private:
+
+  /*
+  -------------------------------------------------------------------
+                          Internal methods
+  -------------------------------------------------------------------
+  */
+
+  /*!
+   * @brief Copy image data
+   *
+   * @param other_image Input image with new image data
+   *
+   * @return true if it is successful, otherwise false.
+   *
+   * Copy image data from @a other_image to MEImage image data.
+   *
+   */
+
+  bool _Copy(const MEImage& other_image);
+
+  /*!
+   * @brief Inherent initialization function
+   *
+   * @param width Width of the image
+   * @param height Height of the image
+   * @param layer Number of color channels of the image
+   *
+   * Initialization function of MEImage class which allocates
+   * memory to internal MEImage image and sets its properties.
+   *
+   */
+
+  void _Init(int width, int height, int layer);
+
+  /*!
+   * @brief Compute an image to a different color space
+   *
+   * @param mode Mode of the conversion
+   *
+   * Currently, the internal function allows to use a few
+   * mode to convert an image between color spaces.
+   * Current supported conversions (@a mode):
+   * - RGBtoYUV: RGB to YUV color space,
+   * - RGBtoYIQ: RGB to YIQ color space.
+   *
+   */
+
+  void ComputeColorSpace(ColorSpaceConvertType mode);
+
+private:
+  /// This matrix stores the matrix of the actual color space transform
+  float TransformMatrix[3][3];
+  /// The OpenCV image which contains the image data
+  void* cvImg;
+};
+
+/** @} */
+
+#endif
diff --git a/package_bgs/ck/MotionDetection.cpp b/package_bgs/ck/MotionDetection.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9cb8e79bcb4e8059d99ded840906f9020da6f394
--- /dev/null
+++ b/package_bgs/ck/MotionDetection.cpp
@@ -0,0 +1,1425 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ *  Paper: Csaba, Kertész: Texture-Based Foreground Detection, International Journal of Signal Processing,
+ *  Image Processing and Pattern Recognition (IJSIP), Vol. 4, No. 4, 2011.
+ */
+
+#include "MotionDetection.hpp"
+
+#include "graph.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <cvaux.h>
+#else
+#include <opencv/cvaux.h>
+#endif
+
+#include "MEHistogram.hpp"
+#include "MEImage.hpp"
+
+// Pyramid picture for the tracking
+IplImage *HUOFPyramid;
+// Pyramid picture for the tracking
+IplImage *HUOFPrevPyramid;
+
+// Struct for histogram update data of a pixel
+struct MEPixelDataType
+{
+  float BackgroundRate;
+  int LifeCycle;
+  float *Weights;
+  bool *BackgroundHistogram;
+  float **Histograms;
+  float *PreviousHistogram;
+};
+
+MotionDetection::MotionDetection(DetectorType mode) :
+  MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false),
+  HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special),
+  HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8),
+  HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL),
+  HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01),
+  HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0),
+  HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1),
+  HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1),
+  HUOFCamMovement(false)
+{
+  HUOFPyramid = NULL;
+  HUOFPrevPyramid = NULL;
+  HUOFPoints[0] = NULL;
+  HUOFPoints[1] = NULL;
+  SetMode(mode);
+}
+
+
+MotionDetection::~MotionDetection()
+{
+  if (MDMode != md_NotDefined)
+  {
+    ReleaseData();
+  }
+}
+
+
+void MotionDetection::SetMode(DetectorType newmode)
+{
+  if (MDMode != md_NotDefined && MDMode != newmode)
+  {
+    ReleaseData();
+    Frames = 0;
+    HUOFFrames = -1;
+    HUOFCamMovement = false;
+    HUOFCamMovementX = 0;
+    ReadyMask = false;
+  }
+
+  switch (newmode)
+  {
+    case md_LBPHistograms:
+      MDMode = md_LBPHistograms;
+      break;
+
+    case md_DLBPHistograms:
+      MDMode = md_DLBPHistograms;
+      break;
+
+    default:
+      MDMode = md_LBPHistograms;
+      break;
+  }
+}
+
+
+float MotionDetection::GetParameter(ParametersType param) const
+{
+  float ret = 0.0;
+
+  switch (param)
+  {
+    case mdp_HUProximityThreshold:
+      ret = (float)HUPrThres;
+      break;
+
+    case mdp_HUBackgroundThreshold:
+      ret = (float)HUBackgrThres;
+      break;
+
+    case mdp_HUHistogramLearningRate:
+      ret = (float)HUHistLRate;
+      break;
+
+    case mdp_HUWeightsLearningRate:
+      ret = (float)HUWeightsLRate;
+      break;
+
+    case mdp_HUMinCutWeight:
+      ret = (float)HUMinCutWeight;
+      break;
+
+    case mdp_HUDesiredSamplePixels:
+      ret = (float)HUDesiredSamplePixels;
+      break;
+
+    case mdp_HUHistogramsPerPixel:
+      ret = (float)HUHistogramsPerPixel;
+      break;
+
+    case mdp_HUHistogramArea:
+      ret = (float)HUHistogramArea;
+      break;
+
+    case mdp_HUHistogramBins:
+      ret = (float)HUHistogramBins;
+      break;
+
+    case mdp_HUColorSpace:
+      ret = (float)HUColorSpace;
+      break;
+
+    case mdp_HULBPMode:
+      ret = (float)HULBPMode;
+      break;
+
+    default:
+      break;
+  }
+  return ret;
+}
+
+
+void MotionDetection::SetParameter(ParametersType param, float value)
+{
+  switch (param)
+  {
+    case mdp_HUProximityThreshold:
+      HUPrThres = (float)value;
+      break;
+
+    case mdp_HUBackgroundThreshold:
+      HUBackgrThres = (float)value;
+      break;
+
+    case mdp_HUHistogramLearningRate:
+      HUHistLRate = (float)value;
+      break;
+
+    case mdp_HUWeightsLearningRate:
+      HUWeightsLRate = (float)value;
+      break;
+
+    case mdp_HUMinCutWeight:
+      HUMinCutWeight = (float)value;
+      break;
+
+    case mdp_HUDesiredSamplePixels:
+      HUDesiredSamplePixels = (int)value;
+      break;
+
+    case mdp_HUHistogramsPerPixel:
+      HUHistogramsPerPixel = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramsPerPixel;
+      break;
+
+    case mdp_HUHistogramArea:
+      HUHistogramArea = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramArea;
+      break;
+
+    case mdp_HUHistogramBins:
+      HUHistogramBins = (MDDataState == ps_Uninitialized) ? (int)value : HUHistogramBins;
+      break;
+
+    case mdp_HUColorSpace:
+      HUColorSpace = (MDDataState == ps_Uninitialized) ? (int)value : HUColorSpace;
+      break;
+
+    case mdp_HULBPMode:
+      HULBPMode = (MDDataState == ps_Uninitialized) ? (int)value : HULBPMode;
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MotionDetection::DetectMotions(MEImage& image)
+{
+  switch (MDMode)
+  {
+    case md_LBPHistograms:
+    case md_DLBPHistograms:
+      DetectMotionsHU(image);
+      break;
+
+    default:
+      break;
+  }
+}
+
+
+void MotionDetection::GetMotionsMask(MEImage& mask_image)
+{
+  if (ReadyMask)
+  {
+     mask_image = MaskImage;
+  }
+
+  switch (MDMode)
+  {
+    case md_LBPHistograms:
+    case md_DLBPHistograms:
+      GetMotionsMaskHU(MaskImage);
+      break;
+
+    default:
+      break;
+  }
+
+  ReadyMask = true;
+  mask_image = MaskImage;
+}
+
+
+void MotionDetection::CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives,
+                                         int& ttnegatives, int& ttpositives)
+{
+  if (MDDataState != ps_Successful)
+  {
+    printf("No data for calculation.\n");
+    return;
+  }
+
+  if (referenceimage.GetLayers() != 1)
+    referenceimage.ConvertToGrayscale(MEImage::g_OpenCV);
+
+  referenceimage.Binarize(1);
+
+  MEImage mask_image;
+
+  GetMotionsMask(mask_image);
+
+  if ((mask_image.GetWidth() != referenceimage.GetWidth()) ||
+       (mask_image.GetHeight() != referenceimage.GetHeight()))
+  {
+    printf("Different resolutions of mask<->reference image.\n");
+    return;
+  }
+
+  unsigned char* RefMaskImgData = referenceimage.GetImageData();
+  unsigned char* MaskImgData = mask_image.GetImageData();
+  int RowStart = 0;
+  int RowWidth = referenceimage.GetRowWidth();
+
+  int TrueNegatives = 0;
+  int TruePositives = 0;
+  int TotalTrueNegatives = 0;
+  int TotalTruePositives = 0;
+
+  int ImageFrame = 0;
+
+  if (MDMode == md_LBPHistograms || md_DLBPHistograms)
+  {
+    ImageFrame = HUHistogramArea / 2;
+  }
+
+  for (int y = referenceimage.GetHeight()-ImageFrame-1; y >= ImageFrame; --y)
+  {
+    for (int x = referenceimage.GetWidth()-ImageFrame-1; x >= ImageFrame; --x)
+    {
+      TrueNegatives +=
+          (RefMaskImgData[RowStart+x] == 0) &&
+          (MaskImgData[RowStart+x] == 0);
+      TotalTrueNegatives += (RefMaskImgData[RowStart+x] == 0);
+      TruePositives +=
+          (RefMaskImgData[RowStart+x] == 255) &&
+          (MaskImgData[RowStart+x] == 255);
+      TotalTruePositives += (RefMaskImgData[RowStart+x] == 255);
+    }
+    RowStart += RowWidth;
+  }
+
+  tnegatives = TrueNegatives;
+  ttnegatives = TotalTrueNegatives;
+  tpositives = TruePositives;
+  ttpositives = TotalTruePositives;
+}
+
+
+void MotionDetection::ReleaseData()
+{
+  if (MDMode == md_LBPHistograms || MDMode == md_DLBPHistograms)
+  {
+    ReleaseHUData();
+  }
+}
+
+
+void MotionDetection::InitHUData(int imagewidth, int imageheight)
+{
+  if ((HUImageWidth != imagewidth-HUHistogramArea+1) ||
+       (HUImageHeight != imageheight-HUHistogramArea+1) ||
+       (MDDataState == ps_Uninitialized))
+  {
+    if (MDDataState != ps_Uninitialized)
+    {
+      ReleaseHUData();
+    }
+
+    MDDataState = ps_Initialized;
+
+    HUImageWidth = imagewidth-HUHistogramArea+1;
+    HUImageHeight = imageheight-HUHistogramArea+1;
+
+    HULBPPixelData = new MEPixelDataType**[HUImageWidth / 2];
+
+    for (int i = 0; i < HUImageWidth / 2; ++i)
+    {
+      HULBPPixelData[i] = new MEPixelDataType*[HUImageHeight];
+    }
+
+    for (int i = 0; i < HUImageWidth / 2; ++i)
+      for (int i1 = 0; i1 < HUImageHeight; ++i1)
+    {
+      HULBPPixelData[i][i1] = new MEPixelDataType;
+      HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel];
+      HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel];
+      HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel];
+      for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+        HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins];
+      HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins];
+    }
+
+    // Allocate auxiliary variables
+    HUMaskColumnAddDel = new int*[HUHistogramArea];
+    for (int i = 0; i < HUHistogramArea; ++i)
+      HUMaskColumnAddDel[i] = new int[2];
+
+    HUMaskRowAddDel = new int*[HUHistogramArea];
+    for (int i = 0; i < HUHistogramArea; ++i)
+      HUMaskRowAddDel[i] = new int[2];
+
+    // Generate sample mask
+    SetSampleMaskHU(sm_Circle, HUDesiredSamplePixels);
+
+    // Init HU optical flow data
+    if (MDMode == md_DLBPHistograms)
+      InitHUOFData(imagewidth, imageheight);
+
+    ClearHUData();
+  }
+}
+
+
+void MotionDetection::InitHUOFData(int imagewidth, int imageheight)
+{
+  if (HUOFDataState != ps_Uninitialized)
+  {
+    ReleaseHUOFData();
+  }
+
+  if (HUOFDataState == ps_Uninitialized)
+  {
+    HUOFPointsNumber = imagewidth*imageheight / 1000;
+    HUOFPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1);
+    HUOFPrevPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1);
+    HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber*sizeof(HUOFPoints[0][0]));
+    HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber*sizeof(HUOFPoints[1][0]));
+  }
+}
+
+
+void MotionDetection::ReleaseHUData()
+{
+  if (MDDataState != ps_Uninitialized)
+  {
+    for (int i = 0; i < HUImageWidth / 2; i++)
+      for (int i1 = 0; i1 < HUImageHeight; i1++)
+    {
+      delete[] HULBPPixelData[i][i1]->PreviousHistogram;
+      for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+        delete[] HULBPPixelData[i][i1]->Histograms[i2];
+      delete[] HULBPPixelData[i][i1]->Histograms;
+      delete[] HULBPPixelData[i][i1]->BackgroundHistogram;
+      delete[] HULBPPixelData[i][i1]->Weights;
+      delete HULBPPixelData[i][i1];
+    }
+
+    for (int i = 0; i < HUImageWidth / 2; i++)
+    {
+      delete[] HULBPPixelData[i];
+    }
+    delete[] HULBPPixelData;
+
+    if (MDMode == md_DLBPHistograms)
+      ReleaseHUOFData();
+
+    HUImageWidth = -1;
+    HUImageHeight = -1;
+    HULBPPixelData = NULL;
+    MDDataState = ps_Uninitialized;
+
+    // Release auxiliary variables
+    for (int i = 0; i < HUHistogramArea; ++i)
+      delete[] HUMaskColumnAddDel[i];
+    delete[] HUMaskColumnAddDel;
+
+    for (int i = 0; i < HUHistogramArea; ++i)
+      delete[] HUMaskRowAddDel[i];
+    delete[] HUMaskRowAddDel;
+
+    HUMaskColumnAddDel = NULL;
+    HUMaskRowAddDel = NULL;
+  }
+}
+
+
+void MotionDetection::ReleaseHUOFData()
+{
+  if (MDDataState != ps_Uninitialized)
+  {
+    if (HUOFPyramid)
+    {
+      cvReleaseImage(&HUOFPyramid);
+      HUOFPyramid = NULL;
+    }
+    if (HUOFPrevPyramid)
+    {
+        cvReleaseImage(&HUOFPrevPyramid);
+        HUOFPrevPyramid = NULL;
+    }
+    if (HUOFPoints[0])
+    {
+        cvFree(&HUOFPoints[0]);
+        HUOFPoints[0] = NULL;
+    }
+    if (HUOFPoints[1])
+    {
+        cvFree(&HUOFPoints[1]);
+        HUOFPoints[1] = NULL;
+    }
+    HUOFDataState = ps_Uninitialized;
+  }
+}
+
+
+void MotionDetection::ClearHUData()
+{
+  if (MDDataState != ps_Uninitialized)
+  {
+    for (int i = (HUImageWidth / 2)-1; i >= 0; --i)
+      for (int i1 = HUImageHeight-1; i1 >= 0; --i1)
+    {
+      for (int i2 = HUHistogramsPerPixel-1; i2 >= 0; --i2)
+      {
+        memset(HULBPPixelData[i][i1]->Histograms[i2], 0,
+               HUHistogramBins*sizeof(float));
+        HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel;
+        HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true;
+      }
+      HULBPPixelData[i][i1]->BackgroundRate = 1.0;
+      HULBPPixelData[i][i1]->LifeCycle = 0;
+    }
+    MDDataState = ps_Initialized;
+  }
+}
+
+
+void MotionDetection::DetectMotionsHU(MEImage& image)
+{
+  unsigned char *ImgData = NULL;
+  MEImage newimage = image;
+  float DiffAreas = 0;
+
+  // Init the histogram update data structures if needs be
+  if ((MDDataState == ps_Uninitialized) ||
+      (HUImageWidth != newimage.GetWidth()-HUHistogramArea+1) ||
+      (HUImageHeight != newimage.GetHeight()-HUHistogramArea+1))
+  {
+    InitHUData(newimage.GetWidth(), newimage.GetHeight());
+  }
+
+  if (newimage.GetLayers() == 1)
+  {
+    newimage.ConvertGrayscaleToRGB();
+  }
+
+  MEImage blueimage = newimage;
+  blueimage.ColorSpace(MEImage::csc_RGBtoCIELuv);
+
+  if (HUColorSpace != -1)
+  {
+    newimage.ColorSpace((MEImage::ColorSpaceConvertType)HUColorSpace);
+  }
+
+  if (Frames == 0)
+  {
+    MEImage BlueLayer;
+    blueimage.GetLayer(BlueLayer, 1);
+    BlueLayer.Resize(32, 24);
+    PreviousBlueLayer = BlueLayer;
+  }
+
+  Frames++;
+
+  // Detect the fast, big changes in the scene
+  MEImage BlueLayer;
+  blueimage.GetLayer(BlueLayer, 1);
+  BlueLayer.Resize(32, 24);
+  DiffAreas = BlueLayer.DifferenceAreas(PreviousBlueLayer, 12);
+
+  if (DiffAreas > 80)
+  {
+    MDDataState = ps_Initialized;
+    if (MDMode == md_DLBPHistograms)
+      HUOFDataState = ps_Initialized;
+    printf("Frame: %d - big changes in the scene (%f)", Frames, DiffAreas);
+    Frames = 1;
+    HUOFFrames = -1;
+  }
+  PreviousBlueLayer = BlueLayer;
+
+  if (Frames == 1)
+  {
+    CurrentImage = image;
+    PreviousImage = CurrentImage;
+  } else
+  if (Frames > 1)
+  {
+    PreviousImage = CurrentImage;
+    CurrentImage = image;
+    // Optical flow correction of the camera movements
+    if (MDMode == md_DLBPHistograms)
+    {
+      OpticalFlowCorrection();
+    }
+  }
+
+  newimage.ConvertToGrayscale(MEImage::g_OpenCV);
+
+  if (HULBPMode != -1)
+  {
+    newimage.LBP((MEImage::LBPType)HULBPMode);
+  }
+
+  // Set some auxiliary variables
+  ImgData = newimage.GetImageData();
+  int DivisionOperator = (int)(log(256 / HUHistogramBins) / log(2))+1;
+
+  // Downscale the image
+  for (int i = newimage.GetRowWidth()*newimage.GetHeight()-1; i >= 0; --i)
+  {
+    ImgData[i] >>= DivisionOperator;
+  }
+
+  UpdateModelHU(newimage, HULBPPixelData);
+
+  // Change the state of the HU data structures
+  if (MDDataState == ps_Initialized)
+  {
+    MDDataState = ps_Successful;
+  }
+  HUOFCamMovement = false;
+  ReadyMask = false;
+}
+
+
+void MotionDetection::UpdateModelHU(MEImage& image, MEPixelDataType*** model)
+{
+  float CurrentHistogram[HUHistogramBins], CurrentHistogram2[HUHistogramBins];
+  unsigned char *ImgData = image.GetImageData();
+  int RowWidth = image.GetRowWidth();
+  int RowStart = (HUImageHeight-1)*RowWidth;
+
+  memset(CurrentHistogram, 0, sizeof(CurrentHistogram));
+  // Calculate the first histogram
+  for (int y = HUHistogramArea-1; y >= 0; --y)
+  {
+    for (int x = HUHistogramArea-1; x >= 0; --x)
+    {
+      if ((HUMaskRowAddDel[y][1] > x) && (HUMaskRowAddDel[y][0] <= x) &&
+           (HUMaskColumnAddDel[x][1] > y) && (HUMaskColumnAddDel[x][0] <= y))
+      {
+        CurrentHistogram[ImgData[RowStart+HUImageWidth-1+x]]++;
+      }
+    }
+    RowStart += RowWidth;
+  }
+
+  // This cycle generates the last row of histograms
+  for (int y = HUImageHeight-1; y >= 0; --y)
+  {
+    if (HUImageHeight-1 > y)
+    {
+      // Delete and add a pixel column from the histogram data
+      for (int i = HUHistogramArea-1; i >= 0; --i)
+      {
+        if (HUMaskColumnAddDel[i][0] != -1)
+          CurrentHistogram[ImgData[RowWidth*(y+HUMaskColumnAddDel[i][0])+HUImageWidth-1+i]]++;
+        if (HUMaskColumnAddDel[i][1] != -1)
+          CurrentHistogram[ImgData[RowWidth*(y+HUMaskColumnAddDel[i][1])+HUImageWidth-1+i]]--;
+      }
+    }
+
+    if (y % 2 == HUImageWidth % 2)
+    {
+      MEPixelDataType* PixelData = model[(HUImageWidth-1) / 2][y];
+
+      // Allocate and initialize the pixel data if needs be
+      if (!PixelData)
+      {
+        // Memory allocation
+        PixelData = new MEPixelDataType;
+        PixelData->Weights = new float[HUHistogramsPerPixel];
+        PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel];
+        PixelData->Histograms = new float*[HUHistogramsPerPixel];
+        for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+          PixelData->Histograms[i2] = new float[HUHistogramBins];
+        PixelData->PreviousHistogram = new float[HUHistogramBins];
+
+        for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+        {
+          memcpy(PixelData->Histograms[i], CurrentHistogram, sizeof(CurrentHistogram));
+          PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+          PixelData->BackgroundHistogram[i] = true;
+        }
+        PixelData->BackgroundRate = 1.0;
+        PixelData->LifeCycle = 0;
+        memcpy(PixelData->PreviousHistogram, CurrentHistogram, sizeof(CurrentHistogram));
+
+        model[(HUImageWidth-1) / 2][y] = PixelData;
+      } else {
+        bool InitHistograms = (MDDataState == ps_Initialized);
+
+        if (MDDataState != ps_Initialized && HUOFCamMovement)
+        {
+          // Histogram intersection between the previous and the current histogram
+          float Difference = 0.0;
+          for (int i1 = HUHistogramBins-1; i1 >= 0; --i1)
+          {
+            Difference += (float)(CurrentHistogram[i1] < PixelData->PreviousHistogram[i1] ?
+                CurrentHistogram[i1] : PixelData->PreviousHistogram[i1]);
+          }
+          Difference /= HUSamplePixels;
+
+          if (Difference < HUBackgrThres)
+            InitHistograms = true;
+        }
+        if (InitHistograms)
+        {
+          // Copy the histogram data to the HU data structures
+          for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+          {
+            memcpy(PixelData->Histograms[i], CurrentHistogram, sizeof(CurrentHistogram));
+            PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+            PixelData->BackgroundHistogram[i] = true;
+          }
+          memcpy(PixelData->PreviousHistogram, CurrentHistogram, sizeof(CurrentHistogram));
+          PixelData->BackgroundRate = 1.0;
+          PixelData->LifeCycle = 0;
+        } else {
+          // Update the HU data structures
+          UpdateHUPixelData(PixelData, CurrentHistogram);
+
+          if (MDMode == md_DLBPHistograms)
+          {
+            memcpy(PixelData->PreviousHistogram, CurrentHistogram, sizeof(CurrentHistogram));
+          }
+        }
+      }
+    }
+
+    // Copy the histogram
+    memcpy(CurrentHistogram2, CurrentHistogram, sizeof(CurrentHistogram));
+
+    // This cycle generates a column of histograms
+    for (int x = HUImageWidth-2; x >= 0; --x)
+    {
+      RowStart = RowWidth*y;
+
+      // Delete and add a pixel column from the histogram data
+      for (int i = HUHistogramArea-1; i >= 0; --i)
+      {
+        if (HUMaskRowAddDel[i][0] != -1)
+          CurrentHistogram2[ImgData[RowStart+x+HUMaskRowAddDel[i][0]]]++;
+        if (HUMaskRowAddDel[i][1] != -1)
+          CurrentHistogram2[ImgData[RowStart+x+HUMaskRowAddDel[i][1]]]--;
+
+        RowStart += RowWidth;
+      }
+      if (x % 2 == 0)
+      {
+        MEPixelDataType* PixelData = model[x / 2][y];
+
+        // Allocate and initialize the pixel data if needs be
+        if (!PixelData)
+        {
+          // Memory allocation
+          PixelData = new MEPixelDataType;
+          PixelData->Weights = new float[HUHistogramsPerPixel];
+          PixelData->BackgroundHistogram = new bool[HUHistogramsPerPixel];
+          PixelData->Histograms = new float*[HUHistogramsPerPixel];
+          for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+            PixelData->Histograms[i2] = new float[HUHistogramBins];
+          PixelData->PreviousHistogram = new float[HUHistogramBins];
+
+          for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+          {
+            memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2));
+            PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+            PixelData->BackgroundHistogram[i] = true;
+          }
+          PixelData->BackgroundRate = 1.0;
+          PixelData->LifeCycle = 0;
+          model[x / 2][y] = PixelData;
+          memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+        } else {
+          bool InitHistograms = (MDDataState == ps_Initialized);
+
+          if (MDDataState != ps_Initialized && HUOFCamMovement)
+          {
+            // Histogram intersection between the previous and the current histogram
+            float Difference = 0.0;
+            for (int i1 = HUHistogramBins-1; i1 >= 0; --i1)
+            {
+              Difference += (float)(CurrentHistogram2[i1] < PixelData->PreviousHistogram[i1] ?
+                  CurrentHistogram2[i1] : PixelData->PreviousHistogram[i1]);
+            }
+            Difference /= HUSamplePixels;
+
+            if (Difference < HUBackgrThres)
+              InitHistograms = true;
+          }
+          if (InitHistograms)
+          {
+            // Copy the histogram data to the HU data structures
+            for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+            {
+              memcpy(PixelData->Histograms[i], CurrentHistogram2, sizeof(CurrentHistogram2));
+              PixelData->Weights[i] = 1.0 / HUHistogramsPerPixel;
+              PixelData->BackgroundHistogram[i] = true;
+            }
+            memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+            PixelData->BackgroundRate = 1.0;
+            PixelData->LifeCycle = 0;
+          } else {
+            // Update the HU data structures
+            UpdateHUPixelData(PixelData, CurrentHistogram2);
+
+            if (MDMode == md_DLBPHistograms)
+            {
+              memcpy(PixelData->PreviousHistogram, CurrentHistogram2, sizeof(CurrentHistogram2));
+            }
+          }
+        }
+      }
+
+    }
+  }
+}
+
+
+void MotionDetection::UpdateHUPixelData(MEPixelDataType* PixelData, const float *histogram)
+{
+  int MaxIndex = 0;
+  float MaxValue = -1;
+  bool Replace = true;
+  float IntersectionResults[HUHistogramsPerPixel];
+
+  PixelData->LifeCycle++;
+  PixelData->BackgroundRate = 0.0;
+
+  // Compute intersection between the currect and older histograms
+  for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+  {
+    // Histogram intersection
+    float Difference = 0.0;
+    for (int i1 = HUHistogramBins-1; i1 >= 0; --i1)
+    {
+      Difference += (float)histogram[i1] < PixelData->Histograms[i][i1] ?
+          (float)histogram[i1] : PixelData->Histograms[i][i1];
+    }
+
+    IntersectionResults[i] = (float)Difference / (float)(HUSamplePixels);
+
+    if (PixelData->BackgroundHistogram[i] &&
+        IntersectionResults[i] > PixelData->BackgroundRate)
+    {
+      PixelData->BackgroundRate = IntersectionResults[i];
+    }
+
+    if (MaxValue < IntersectionResults[i])
+    {
+      MaxValue = IntersectionResults[i];
+      MaxIndex = i;
+    }
+
+    Replace = Replace && (IntersectionResults[i] < HUPrThres);
+  }
+
+  // Replace the histogram with the lowest weight
+  if (Replace)
+  {
+    // Find the histogram with minimal weight
+    int MinIndex = 0;
+    float MinValue = PixelData->Weights[0];
+    for (int i1 = HUHistogramsPerPixel-1; i1 > 0; --i1)
+    {
+      if (MinValue > PixelData->Weights[i1])
+      {
+        MinValue = PixelData->Weights[i1];
+        MinIndex = i1;
+      }
+    }
+
+    PixelData->Weights[MinIndex] = 0.01;
+    for (int i1 = HUHistogramBins-1; i1 >= 0; --i1)
+      PixelData->Histograms[MinIndex][i1] = (float)histogram[i1];
+    PixelData->BackgroundHistogram[MinIndex] = 0;
+
+    // Normalize the weights
+    float sum = 0;
+    for (int i1 = HUHistogramsPerPixel-1; i1 >= 0; --i1)
+      sum += PixelData->Weights[i1];
+
+    for (int i1 = HUHistogramsPerPixel-1; i1 >= 0; --i1)
+      PixelData->Weights[i1] = PixelData->Weights[i1] / sum;
+
+    return;
+  }
+
+  float LearningRate = HUHistLRate;
+
+  if (PixelData->LifeCycle < 100)
+    LearningRate += (float)(100-PixelData->LifeCycle) / 100;
+  else
+  if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40)
+    LearningRate += (HUOFFrames < 80 ? 0.05 : 0);
+
+  // Match was found -> Update the histogram of the best match
+  for (int i = HUHistogramBins-1; i >= 0; --i)
+  {
+    PixelData->Histograms[MaxIndex][i] *= (1.0-LearningRate);
+    PixelData->Histograms[MaxIndex][i] += LearningRate*(float)histogram[i];
+  }
+
+  LearningRate = HUWeightsLRate;
+  if (PixelData->LifeCycle < 100)
+    LearningRate += (float)(100-PixelData->LifeCycle) / 100;
+  else
+  if (MDMode == md_DLBPHistograms && HUOFFrames != -1 && HUOFFrames < 40)
+    LearningRate += (HUOFFrames < 80 ? 0.05 : 0);
+
+  // Update the weights of the histograms
+  for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+  {
+    PixelData->Weights[i] =
+        (LearningRate*(i == MaxIndex)+(1.0-LearningRate)*PixelData->Weights[i]);
+  }
+
+  // Order and select the background histograms
+  float Weights[HUHistogramsPerPixel][2];
+
+  for (int i = HUHistogramsPerPixel-1; i >= 0; --i)
+  {
+    Weights[i][0] = (float)i;
+    Weights[i][1] = PixelData->Weights[i];
+  }
+
+  for (int i1 = HUHistogramsPerPixel-1; i1 >= 2; --i1)
+    for (int i = i1; i >= 1; --i)
+  {
+    if (Weights[i][1] <= Weights[i-1][1])
+    {
+      float tmp = Weights[i][0];
+      float tmp2 = Weights[i][1];
+
+      Weights[i][0] = Weights[i-1][0];
+      Weights[i][1] = Weights[i-1][1];
+
+      Weights[i-1][0] = tmp;
+      Weights[i-1][1] = tmp2;
+    }
+  }
+
+  float Sum = 0;
+  int i = 0;
+
+  for (i = HUHistogramsPerPixel-1; i >= 0; --i)
+  {
+    Sum += Weights[i][1];
+    PixelData->BackgroundHistogram[(int)Weights[i][0]] = true;
+
+    if (Sum > HUBackgrThres)
+      break;
+  }
+  for (int i1 = i-1; i1 >= 0; --i1)
+  {
+    PixelData->BackgroundHistogram[(int)Weights[i1][0]] = false;
+  }
+}
+
+
+void MotionDetection::OpticalFlowCorrection()
+{
+  IplImage *PreviousGray = NULL, *CurrentGray = NULL;
+  char* PointsStatus = (char*)cvAlloc(HUOFPointsNumber);
+  int i = 0, i1 = 0;
+
+  if (HUOFFrames != -1)
+    HUOFFrames++;
+
+  // Convert the images into grayscale
+  if (CurrentImage.GetLayers() > 1)
+  {
+    CurrentGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1);
+    cvCvtColor(CurrentImage.GetIplImage(), CurrentGray, CV_BGR2GRAY);
+  } else
+    CurrentGray = (IplImage*)CurrentImage.GetIplImage();
+  if (PreviousImage.GetLayers() > 1)
+  {
+    PreviousGray = cvCreateImage(cvGetSize(CurrentImage.GetIplImage()), IPL_DEPTH_8U, 1);
+    cvCvtColor(PreviousImage.GetIplImage(), PreviousGray, CV_BGR2GRAY);
+  } else
+    PreviousGray = (IplImage*)PreviousImage.GetIplImage();
+
+  if (HUOFDataState != ps_Successful)
+  {
+    printf("Search new corners\n");
+    IplImage* TempEig = cvCreateImage(cvGetSize(CurrentGray), 32, 1 );
+    IplImage* Temp = cvCreateImage(cvGetSize(CurrentGray), 32, 1 );
+    double MinDistance = (CurrentImage.GetWidth()+CurrentImage.GetHeight()) / 20;
+    HUOFPointsNumber = MaxTrackedPoints = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
+
+    // Search good trackable points
+    cvGoodFeaturesToTrack(PreviousGray, TempEig, Temp,
+                          HUOFPoints[0], &HUOFPointsNumber,
+                          0.01, MinDistance, NULL, 3);
+    MaxTrackedPoints = HUOFPointsNumber;
+    // Release temporary images
+    cvReleaseImage(&TempEig);
+    cvReleaseImage(&Temp);
+    // Realloc the point status array
+    if (PointsStatus)
+    {
+      cvFree(&PointsStatus);
+      PointsStatus = NULL;
+    }
+
+    if (MaxTrackedPoints < 2)
+    {
+      HUOFDataState = ps_Initialized;
+      HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
+      return;
+    } else
+      HUOFDataState = ps_Successful;
+      PointsStatus = (char*)cvAlloc(HUOFPointsNumber);
+  }
+
+  cvCalcOpticalFlowPyrLK(PreviousGray, CurrentGray, HUOFPrevPyramid, HUOFPyramid,
+                         HUOFPoints[0], HUOFPoints[1], HUOFPointsNumber,
+                         cvSize(10, 10), 3, PointsStatus, NULL,
+                         cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 5, 1), 0);
+
+  // Count the distances of the tracked points
+  int Distances[HUOFPointsNumber][3];
+  int DistanceMax = 0;
+  for (i = 0; i < HUOFPointsNumber; ++i)
+  {
+    int DiffX = (int)MERound(HUOFPoints[1][i].x-HUOFPoints[0][i].x);
+    int DiffY = (int)MERound(HUOFPoints[1][i].y-HUOFPoints[0][i].y);
+    if ((PointsStatus[i] == 1) && !((DiffX == 0) && (DiffY == 0)))
+    {
+      bool found = false;
+      // Create a list from the differences to count them
+      for (i1 = 0; i1 < DistanceMax; ++i1)
+      {
+        if ((Distances[i1][0] == DiffX) &&
+             (Distances[i1][1] == DiffY))
+        {
+          Distances[i1][2]++;
+          found = true;
+          break;
+        }
+      }
+      if ((!found) && !((DiffX == 0) && (DiffY == 0)))
+      {
+        Distances[DistanceMax][0] = (int)MERound(HUOFPoints[1][i].x-HUOFPoints[0][i].x);
+        Distances[DistanceMax][1] = (int)MERound(HUOFPoints[1][i].y-HUOFPoints[0][i].y);
+        Distances[DistanceMax][2] = 1;
+        DistanceMax++;
+      }
+    }
+  }
+
+  // Sort the results
+  for (int i1 = DistanceMax-1; i1 >= 2; --i1)
+    for (int i = i1; i >= 1; --i)
+  {
+    if ((Distances[i][2] > Distances[i-1][2]) ||
+         ((Distances[i][2] == Distances[i-1][2]) &&
+         (abs(Distances[i][0])+abs(Distances[i][1]) <
+          abs(Distances[i-1][0])+abs(Distances[i-1][1]))))
+    {
+      int tmp = Distances[i][0];
+      int tmp2 = Distances[i][1];
+      int tmp3 = Distances[i][2];
+
+      Distances[i][0] = Distances[i-1][0];
+      Distances[i][1] = Distances[i-1][1];
+      Distances[i][2] = Distances[i-1][2];
+
+      Distances[i-1][0] = tmp;
+      Distances[i-1][1] = tmp2;
+      Distances[i-1][2] = tmp3;
+    }
+  }
+
+  float MoveX = 0.0;
+  float MoveY = 0.0;
+  int SampleNums = 0;
+  float DistanceMeasure = 0.0;
+
+  // Calculate the final camera movement
+  for (i = 0; i < DistanceMax; ++i)
+  {
+    if ((Distances[i][2] <= MaxTrackedPoints / 10))
+      break;
+
+    if (i > 0)
+    {
+      DistanceMeasure += (Distances[i][0]-Distances[i-1][0])*(Distances[i][0]-Distances[i-1][0]);
+      DistanceMeasure += (Distances[i][1]-Distances[i-1][1])*(Distances[i][1]-Distances[i-1][1]);
+    }
+
+    MoveX += Distances[i][0]*Distances[i][2];
+    MoveY += Distances[i][1]*Distances[i][2];
+    SampleNums += Distances[i][2];
+  }
+
+  if (SampleNums > 0)
+  {
+    MoveX = MERound(MoveX / SampleNums);
+    MoveY = MERound(MoveY / SampleNums);
+  }
+
+  if (!((MoveX == 0) && (MoveY == 0)) &&
+        (SampleNums > MaxTrackedPoints / 2))
+  {
+    HUOFCamMovementX += (int)MoveX;
+    int HUOFCamMovementY = (int)MoveY;
+    int MaxX = (HUImageWidth / 2)-1;
+    int MaxY = HUImageHeight-1;
+/*
+    printf("-----------\n");
+
+    for (i = 0; i < DistanceMax; ++i)
+      printf("%d: %d,%d\n", Distances[i][2], Distances[i][0], Distances[i][1]);
+
+    printf("FINAL: %d,%d,%1.2f\n", (int)MoveX, (int)MoveY, DistanceMeasure);
+    printf("-----------\n");
+    printf("Camera movement: %d,%d,%d (max: %d, current: %d)\n",
+           SampleNums, HUOFCamMovementX, HUOFCamMovementY, MaxTrackedPoints, HUOFPointsNumber);
+*/
+    HUOFFrames = 0;
+    HUOFCamMovement = true;
+
+    if (!(HUOFCamMovementY == 0 && HUOFCamMovementX >= -1 && HUOFCamMovementX <= 1))
+    {
+      MEPixelDataType* PreviousData[MaxX+1][MaxY+1];
+
+      // Camera movement being happened
+      for (int y = MaxY; y >= 0; --y)
+        for (int x = MaxX; x >= 0; --x)
+      {
+        PreviousData[x][y] = NULL;
+      }
+
+      // Move the LBP data to new locations
+      for (int y = MaxY; y >= 0; --y)
+        for (int x = MaxX; x >= 0; --x)
+      {
+        int NewX = x+(HUOFCamMovementX / 2);
+        int NewY = y+HUOFCamMovementY;
+
+        if (NewX >= 0 && NewX <= MaxX &&
+             NewY >= 0 && NewY <= MaxY)
+        {
+          if (HULBPPixelData[NewX][NewY])
+          {
+            PreviousData[NewX][NewY] = HULBPPixelData[NewX][NewY];
+            HULBPPixelData[NewX][NewY] = NULL;
+            if (PreviousData[x][y])
+            {
+              HULBPPixelData[NewX][NewY] = PreviousData[x][y];
+              PreviousData[x][y] = NULL;
+            } else {
+              HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y];
+              HULBPPixelData[x][y] = NULL;
+            }
+          } else {
+            if (PreviousData[x][y])
+            {
+              HULBPPixelData[NewX][NewY] = PreviousData[x][y];
+              PreviousData[x][y] = NULL;
+            } else {
+              HULBPPixelData[NewX][NewY] = HULBPPixelData[x][y];
+              HULBPPixelData[x][y] = NULL;
+            }
+          }
+        } else {
+          if (HULBPPixelData[x][y])
+          {
+            delete[] HULBPPixelData[x][y]->PreviousHistogram;
+            for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+              delete[] HULBPPixelData[x][y]->Histograms[i2];
+            delete[] HULBPPixelData[x][y]->Histograms;
+            delete[] HULBPPixelData[x][y]->BackgroundHistogram;
+            delete[] HULBPPixelData[x][y]->Weights;
+            delete HULBPPixelData[x][y];
+            HULBPPixelData[x][y] = NULL;
+          }
+        }
+      }
+      // Release unused data
+      for (int y = MaxY; y >= 0; --y)
+        for (int x = MaxX; x >= 0; --x)
+      {
+        if (PreviousData[x][y])
+        {
+          delete[] PreviousData[x][y]->PreviousHistogram;
+          for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2)
+            delete[] PreviousData[x][y]->Histograms[i2];
+          delete[] PreviousData[x][y]->Histograms;
+          delete[] PreviousData[x][y]->BackgroundHistogram;
+          delete[] PreviousData[x][y]->Weights;
+          delete PreviousData[x][y];
+          PreviousData[x][y] = NULL;
+        }
+      }
+      HUOFCamMovementX = HUOFCamMovementX % 1;
+    }
+  }
+
+  i1 = 0;
+  // Throw the missed points away
+  for (i = 0; i < HUOFPointsNumber; ++i)
+  {
+    if (PointsStatus[i] == 1)
+    {
+      HUOFPoints[0][i1] = HUOFPoints[1][i];
+      i1++;
+    }
+  }
+  HUOFPointsNumber -= i+1-i1;
+
+  if (HUOFPointsNumber < MaxTrackedPoints / 2)
+  {
+    printf("Re-init the optical flow\n");
+    HUOFDataState = ps_Initialized;
+    HUOFPointsNumber = CurrentImage.GetWidth()*CurrentImage.GetHeight() / 1000;
+  }
+  // Free memory
+  if (PreviousGray != PreviousImage.GetIplImage())
+    cvReleaseImage(&PreviousGray);
+  if (CurrentGray != CurrentImage.GetIplImage())
+    cvReleaseImage(&CurrentGray);
+  cvFree(&PointsStatus);
+}
+
+
+void MotionDetection::GetMotionsMaskHU(MEImage& mask_image)
+{
+  if (MDDataState != ps_Successful)
+  {
+    mask_image.Clear();
+    return;
+  }
+
+  // Reallocate the mask image if needs be
+  if ((HUImageWidth+HUHistogramArea-1 != mask_image.GetWidth()) ||
+       (HUImageHeight+HUHistogramArea-1 != mask_image.GetHeight()) ||
+       (mask_image.GetLayers() != 1))
+  {
+    mask_image.Realloc(HUImageWidth+HUHistogramArea-1,
+                       HUImageHeight+HUHistogramArea-1, 1);
+  }
+  mask_image.Clear();
+  // Generate the mask image
+  unsigned char* MaskImgData = mask_image.GetImageData();
+  int RowStart = (mask_image.GetHeight()-HUHistogramArea / 2)*mask_image.GetRowWidth();
+  int RowWidth = mask_image.GetRowWidth();
+
+  // Generate a graph about the histogram data
+  Graph::node_id Nodes[HUImageWidth / 2][HUImageHeight];
+  Graph *LBPGraph = new Graph();
+
+  for (int x = (HUImageWidth / 2)-1; x >= 0; --x)
+    for (int y = HUImageHeight-1; y >= 0; --y)
+    {
+      Nodes[x][y] = LBPGraph->add_node();
+    }
+
+  for (int x = (HUImageWidth / 2)-1; x >= 0; --x)
+    for (int y = HUImageHeight-1; y >= 0; --y)
+    {
+      LBPGraph->set_tweights(Nodes[x][y], 1,
+                             (short int)(HUMinCutWeight*(1-HULBPPixelData[x][y]->BackgroundRate)));
+
+      if (x > 0 && y > 0)
+      {
+        LBPGraph->add_edge(Nodes[x][y], Nodes[x-1][y], 1, 1);
+        LBPGraph->add_edge(Nodes[x][y], Nodes[x][y-1], 1, 1);
+      }
+    }
+
+  LBPGraph->maxflow();
+
+  for (int x = (HUImageWidth / 2)-1; x >= 0; --x)
+    for (int y = HUImageHeight-1; y >= 0; --y)
+    {
+      if (LBPGraph->what_segment(Nodes[x][y]) == Graph::SINK)
+        HULBPPixelData[x][y]->BackgroundRate = 0.0;
+      else
+        HULBPPixelData[x][y]->BackgroundRate = 1.0;
+    }
+
+  delete LBPGraph;
+  LBPGraph = NULL;
+  for (int y = HUImageHeight-1; y >= 0; --y)
+  {
+    for (int x = HUImageWidth-1; x >= 0; --x)
+    {
+      if (y % 2 == (x+1) % 2)
+        MaskImgData[RowStart+x+(HUHistogramArea / 2)] =
+            (HULBPPixelData[x / 2][y]->BackgroundRate == 0.0) ? 255 : 0;
+      else {
+        MaskImgData[RowStart+x+(HUHistogramArea / 2)] =
+            ((int)(x > 1 && HULBPPixelData[(x / 2)-1][y]->BackgroundRate == 0.0)+
+            (int)(x < mask_image.GetWidth()-HUHistogramArea-1 &&
+                  HULBPPixelData[(x / 2)+1][y]->BackgroundRate == 0.0)+
+            (int)(y > 0 && HULBPPixelData[x / 2][y-1]->BackgroundRate == 0.0)+
+            (int)(y < mask_image.GetHeight()-HUHistogramArea &&
+                  HULBPPixelData[x / 2][y+1]->BackgroundRate == 0.0) > 1)
+            ? 255 : 0;
+      }
+    }
+    RowStart -= RowWidth;
+  }
+
+  cvFloodFill(mask_image.GetIplImage(), cvPoint(0, 0), cvScalar(128, 128, 128, 128),
+              cvScalar(0, 0, 0, 0), cvScalar(0, 0, 0, 0));
+  for (int i = ((IplImage*)mask_image.GetIplImage())->widthStep*((IplImage*)mask_image.GetIplImage())->height-1; i >= 0; --i)
+  {
+    if (MaskImgData[i] == 128)
+    {
+      MaskImgData[i] = 0;
+    } else
+    if (MaskImgData[i] == 0)
+    {
+      MaskImgData[i] = 255;
+    }
+  }
+  // Apply an erode operator
+  mask_image.Erode(1);
+}
+
+
+void MotionDetection::SetSampleMaskHU(SampleMaskType mask_type, int desiredarea)
+{
+  if (HUMaskColumnAddDel == NULL || HUMaskRowAddDel == NULL)
+  {
+    printf("Auxiliary variables are NULL\n");
+    return;
+  }
+
+  // Generate a mask for computing the histograms
+  IplImage *MaskImage = cvCreateImage(cvSize(HUHistogramArea, HUHistogramArea), 8, 1);
+  int DesiredArea = desiredarea <= 0 ? HUHistogramBins*2 : desiredarea;
+  int CalculationMask[HUHistogramArea][HUHistogramArea];
+  int SquareSide = (int)MERound(sqrt(DesiredArea));
+  int CircleRadius = (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE));
+  int EllipseA = (int)MERound(HUHistogramArea / 2+1);
+  int EllipseB = (int)MERound(DesiredArea / (EllipseA*1.2*ME_PI_VALUE));
+
+  cvSetZero(MaskImage);
+
+  switch (mask_type)
+  {
+    case sm_Circle:
+      cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
+               CircleRadius, CV_RGB(1, 1, 1), -1);
+      break;
+
+    case sm_Square:
+      cvRectangle(MaskImage,
+                  cvPoint(HUHistogramArea / 2-SquareSide / 2, HUHistogramArea / 2-SquareSide / 2),
+                  cvPoint(HUHistogramArea / 2+SquareSide / 2, HUHistogramArea / 2+SquareSide / 2),
+                  CV_RGB(1, 1, 1), -1);
+      break;
+
+    case sm_Ellipse:
+      cvEllipse(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
+                cvSize(EllipseA, EllipseB), 45, 0, 360,
+                CV_RGB(1, 1, 1), -1);
+      break;
+
+    case sm_RandomPixels:
+      HUSamplePixels = 0;
+      while (HUSamplePixels != DesiredArea)
+      {
+        int i = rand() % HUHistogramArea;
+        int j = rand() % HUHistogramArea;
+
+        if (MaskImage->imageData[i*MaskImage->widthStep+j] == 0)
+        {
+          MaskImage->imageData[i*MaskImage->widthStep+j] = 1;
+          HUSamplePixels++;
+        }
+      }
+      break;
+
+    default:
+      cvCircle(MaskImage, cvPoint(HUHistogramArea / 2, HUHistogramArea / 2),
+               (int)MERound(sqrt((float)DesiredArea / ME_PI_VALUE)), CV_RGB(1, 1, 1), -1);
+      break;
+  }
+
+  HUSamplePixels = 0;
+  memset(CalculationMask, 0, sizeof(CalculationMask));
+
+  for (int i = 0; i < HUHistogramArea; ++i)
+    for (int i1 = 0; i1 < HUHistogramArea; ++i1)
+  {
+    if (MaskImage->imageData[i*MaskImage->widthStep+i1] != 0)
+    {
+      HUSamplePixels++;
+      CalculationMask[i][i1] = 1;
+    } else {
+      CalculationMask[i][i1] = 0;
+    }
+  }
+
+  // Fill an auxiliary variable for fast computing with data
+  for (int i = 0; i < HUHistogramArea; ++i)
+  {
+    HUMaskColumnAddDel[i][0] = -1;
+    for (int i1 = 0; i1 < HUHistogramArea; ++i1)
+    {
+      if (CalculationMask[i][i1] != 0)
+      {
+        HUMaskColumnAddDel[i][0] = i1;
+        break;
+      }
+    }
+    HUMaskColumnAddDel[i][1] = -1;
+    for (int i1 = HUHistogramArea-1; i1 >= 0; --i1)
+    {
+      if (CalculationMask[i][i1] != 0)
+      {
+        HUMaskColumnAddDel[i][1] = i1+1;
+        break;
+      }
+    }
+  }
+  // Fill an auxiliary variable for fast computing with data
+  for (int i = 0; i < HUHistogramArea; ++i)
+  {
+    HUMaskRowAddDel[i][0] = -1;
+    for (int i1 = 0; i1 < HUHistogramArea; ++i1)
+    {
+      if (CalculationMask[i1][i] != 0)
+      {
+        HUMaskRowAddDel[i][0] = i1;
+        break;
+      }
+    }
+    HUMaskRowAddDel[i][1] = -1;
+    for (int i1 = HUHistogramArea-1; i1 >= 0; --i1)
+    {
+      if (CalculationMask[i1][i] != 0)
+      {
+        HUMaskRowAddDel[i][1] = i1+1;
+        break;
+      }
+    }
+  }
+  // Freeing memory
+  cvReleaseImage(&MaskImage);
+}
+
diff --git a/package_bgs/ck/MotionDetection.hpp b/package_bgs/ck/MotionDetection.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6e11521d493b40ef78ce069d0ad854ac627a4748
--- /dev/null
+++ b/package_bgs/ck/MotionDetection.hpp
@@ -0,0 +1,401 @@
+/*
+ *  This file is part of the AiBO+ project
+ *
+ *  Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com)
+ *
+ *  AiBO+ is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  AiBO+ is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef MotionDetection_hpp
+#define MotionDetection_hpp
+
+/**
+ *  @addtogroup mindeye
+ *  @{
+ */
+
+#include "MEDefs.hpp"
+#include "MEImage.hpp"
+
+class CvBGStatModel;
+class CvPoint2D32f;
+
+// Struct for histogram update data of a pixel
+struct MEPixelDataType;
+
+/**
+ * MotionDetection
+ * @brief Extract moving objects from image sequence
+ */
+class MotionDetection
+{
+public:
+
+  /// Types of motion detection
+  typedef enum
+  {
+    md_Min = 0,               /*!< Minimum value */
+    md_NotDefined = md_Min,   /*!< Not defined */
+    md_DLBPHistograms,        /*!< Dynamic LBP */
+    md_LBPHistograms,         /*!< Normal LBP */
+    md_Max = md_LBPHistograms /*!< Maximum value */
+  } DetectorType;
+
+  /// Types of sample mask
+  typedef enum
+  {
+    sm_Min = 0,              /*!< Minimum value */
+    sm_Circle = sm_Min,      /*!< Circle */
+    sm_Square,               /*!< Square */
+    sm_Ellipse,              /*!< Ellipse */
+    sm_RandomPixels,         /*!< Random pixels */
+    sm_Max = sm_RandomPixels /*!< Maximum value */
+  } SampleMaskType;
+
+  /// Types of motion detection parameters
+  typedef enum
+  {
+    mdp_Min = 0,                         /*!< Minimum value */
+    mdp_HUProximityThreshold = mdp_Min,  /*!< Proximity threshold */
+    mdp_HUBackgroundThreshold,           /*!< Background threshold */
+    mdp_HUHistogramLearningRate,         /*!< Histogram learning rate */
+    mdp_HUWeightsLearningRate,           /*!< Weights learning rate */
+    mdp_HUMinCutWeight,                  /*!< Minimum cut weight */
+    mdp_HUDesiredSamplePixels,           /*!< Desired sample pixels */
+    mdp_HUHistogramsPerPixel,            /*!< Histogram per pixel */
+    mdp_HUHistogramArea,                 /*!< Histogram area */
+    mdp_HUHistogramBins,                 /*!< Histogram bins */
+    mdp_HUColorSpace,                    /*!< Color space */
+    mdp_HULBPMode,                       /*!< LBP mode */
+    mdp_Max = mdp_HULBPMode              /*!< Maximum value */
+  } ParametersType;
+
+  /*!
+   * @brief Class constructor
+   *
+   * @param mode Detection mode
+   *
+   * Class constructor with the possibility to specify the detection mode.
+   * The default is dynamic LBP.
+   *
+   */
+
+  MotionDetection(DetectorType mode = md_DLBPHistograms);
+  /// Destructor of class
+  ~MotionDetection();
+
+  /*
+  -------------------------------------------------------------------
+                           Motion methods
+  -------------------------------------------------------------------
+  */
+
+  /*!
+   * @brief Set the mode of the motion detection
+   *
+   * @param newmode New mode of detection
+   *
+   * Set the mode of the motion detection.
+   *
+   */
+
+  void SetMode(DetectorType newmode);
+
+  /*!
+   * @brief Get a parameter value of the motion detection
+   *
+   * @param param Parameter of the detection
+   *
+   * @return Queried value
+   *
+   * Get the value of a parameter of the motion detection.
+   *
+   */
+
+  float GetParameter(ParametersType param) const;
+
+  /*!
+   * @brief Set a parameter of the motion detection
+   *
+   * @param param Parameter of the detection
+   * @param value New value
+   *
+   * Set a new value to a parameter of the motion detection.
+   *
+   */
+
+  void SetParameter(ParametersType param, float value);
+
+  /*!
+   * @brief Detect the motions on an image
+   *
+   * @param image Image to process
+   *
+   * The function designed to search motions in image streams
+   * thus it needs to process the image sequence frame by frame.
+   * It processes an image from this sequence and searches moving blobs
+   * on that.
+   *
+   */
+
+  void DetectMotions(MEImage& image);
+
+  /*!
+   * @brief Get mask image with detected motions
+   *
+   * @param mask_image Result mask image
+   *
+   * The function creates a mask image on which the objects are
+   * indicated by white blobs.
+   *
+   */
+
+  void GetMotionsMask(MEImage& mask_image);
+
+  /*!
+   * @brief Calculate results of the motion detection
+   *
+   * @param referenceimage Reference mask image
+   * @param tnegatives True negative pixels
+   * @param tpositives True positive pixels
+   * @param ttnegatives Total true negative pixels
+   * @param ttpositives Total true positive pixels
+   *
+   * The function calculates the results of the motion detection
+   * between the current motion mask and a given reference mask
+   * image.
+   *
+   */
+
+  void CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives,
+                        int& ttnegatives, int& ttpositives);
+
+private:
+
+  /*!
+   * @brief Release data structures
+   *
+   * Function releases the data structures.
+   *
+   */
+
+  void ReleaseData();
+
+  /*
+  -------------------------------------------------------------------
+                    Histogram update methods
+  -------------------------------------------------------------------
+  */
+
+  /*!
+   * @brief Init HU data structures
+   *
+   * @param imagewidth Image width for HU to process
+   * @param imageheight Image height for HU to process
+   *
+   * Function allocates/re-allocates the HU data structures and they
+   * are cleared if needs be.
+   *
+   */
+
+  void InitHUData(int imagewidth, int imageheight);
+
+  /*!
+   * @brief Init HU optical flow data structures
+   *
+   * @param imagewidth Image width for HU to process
+   * @param imageheight Image height for HU to process
+   *
+   * Function allocates/re-allocates the HU optical flow
+   * data structures.
+   *
+   */
+
+  void InitHUOFData(int imagewidth, int imageheight);
+
+  /*!
+   * @brief Release HU data structures
+   *
+   * Function releases the HU data structures.
+   *
+   */
+
+  void ReleaseHUData();
+
+  /*!
+   * @brief Release HU optical flow data structures
+   *
+   * Function releases the HU optical flow data structures.
+   *
+   */
+
+  void ReleaseHUOFData();
+
+  /*!
+   * @brief Clear HU data structures
+   *
+   * Function clears the HU data structures.
+   *
+   */
+
+  void ClearHUData();
+
+  /*!
+   * @brief Get mask image with detected motions by histogram update
+   *
+   * @param mask_image Result mask image
+   *
+   * The function creates a mask image on which the objects are
+   * indicated by white blobs.
+   *
+   */
+
+  void GetMotionsMaskHU(MEImage& mask_image);
+
+  /*!
+   * @brief Set the sample mask
+   *
+   * @param mask_type Type of the mask
+   * @param desiredarea The desired area size of the mask
+   *
+   * The function creates a sample mask with a desired form
+   * (square, circle, ellipse, random pixels) and size.
+   *
+   */
+
+  void SetSampleMaskHU(SampleMaskType mask_type, int desiredarea);
+
+  /*!
+   * @brief Detect the motions on an image with histogram update
+   *
+   * @param image Image to process
+   *
+   * The function designed to search motions in image streams
+   * thus it needs to process the image sequence frame by frame.
+   * It processes an image from this sequence and searches moving blobs
+   * on that. It uses histogram update method.
+   *
+   */
+
+  void DetectMotionsHU(MEImage& image);
+
+  /*!
+   * @brief Update a model
+   *
+   * @param image Image to process
+   * @param model Model to update
+   *
+   * The function updates a histogram model of the image.
+   *
+   */
+
+  void UpdateModelHU(MEImage& image, MEPixelDataType*** model);
+
+  /*!
+   * @brief Update the HU data structure for one pixel
+   *
+   * @param pixeldata Pixel data
+   * @param histogram Current histogram
+   *
+   * This method updates the HU data for one pixel.
+   *
+   */
+
+  void UpdateHUPixelData(MEPixelDataType* pixeldata, const float *histogram);
+
+  /*!
+   * @brief Optical flow correction of the camera movements
+   *
+   * The function trackes some points on the scene if a camera movement is
+   * detected, then the LBP pixel data is corrected.
+   *
+   */
+
+  void OpticalFlowCorrection();
+
+private:
+  // GENERAL VARIABLES
+  /// Motion detection type
+  DetectorType MDMode;
+  /// State of the data structures
+  MEProcessStateType MDDataState;
+  /// Processed number in the image sequence
+  int Frames;
+  /// Store the current image
+  MEImage CurrentImage;
+  /// Store the previous image
+  MEImage PreviousImage;
+  /// Store the current mask image
+  MEImage MaskImage;
+  /// Store the current mask image
+  bool ReadyMask;
+  // HISTOGRAM UPDATE VARIABLES
+  /// Color space (-1 = no conversion)
+  int HUColorSpace;
+  /// LBP calculation mode (-1 = no conversion)
+  int HULBPMode;
+  /// Histograms per pixel
+  int HUHistogramsPerPixel;
+  /// Histogram area
+  int HUHistogramArea;
+  /// Histogram bins
+  int HUHistogramBins;
+  /// Image width for histogram update
+  int HUImageWidth;
+  /// Image height for histogram update
+  int HUImageHeight;
+  /// Data of the LBP histograms
+  MEPixelDataType ***HULBPPixelData;
+  /// Store the previous blue layer
+  MEImage PreviousBlueLayer;
+  /// Histogram proximity threshold
+  float HUPrThres;
+  /// Background selection threshold
+  float HUBackgrThres;
+  /// Histogram learning rate
+  float HUHistLRate;
+  /// Weights learning rate
+  float HUWeightsLRate;
+  /// Pixel number used to calculate the histograms
+  int HUSamplePixels;
+  /// The desired pixel number used to calculate the histograms (-1 = Auto)
+  int HUDesiredSamplePixels;
+  /// Min cut weight
+  float HUMinCutWeight;
+  /// Auxiliary variable for computing the histograms in a column
+  int **HUMaskColumnAddDel;
+  /// Auxiliary variable for computing the histograms in a row
+  int **HUMaskRowAddDel;
+  // OPTICAL FLOW VARIABLES
+  /// State of the optical flow
+  MEProcessStateType HUOFDataState;
+  /// Number of the tracked points with optical flow
+  int HUOFPointsNumber;
+  /// Tracked points
+  CvPoint2D32f* HUOFPoints[2];
+  /// The rest x component of previous camera movement
+  int HUOFCamMovementX;
+  /// Maximum tracked points detected in one cycle
+  int MaxTrackedPoints;
+  /// Processed frame number with optical flow in the image sequence
+  int HUOFFrames;
+  /// Indicator of a new camera movement
+  bool HUOFCamMovement;
+};
+
+/** @} */
+
+#endif
diff --git a/package_bgs/ck/README.TXT b/package_bgs/ck/README.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..d76c6a3438d3b26fb98b3355f6359b2474ccea34
--- /dev/null
+++ b/package_bgs/ck/README.TXT
@@ -0,0 +1,135 @@
+###################################################################
+#                                                                 #
+#    MAXFLOW - software for computing mincut/maxflow in a graph   #
+#                        Version 2.2                              #
+#    http://www.cs.cornell.edu/People/vnk/software.html           #
+#                                                                 #
+#    Yuri Boykov (yuri@csd.uwo.ca)                                #
+#    Vladimir Kolmogorov (vnk@cs.cornell.edu)                     #
+#    2001                                                         #
+#                                                                 #
+###################################################################
+
+1. Introduction.
+
+This software library implements the maxflow algorithm
+described in
+
+	An Experimental Comparison of Min-Cut/Max-Flow Algorithms
+	for Energy Minimization in Vision.
+	Yuri Boykov and Vladimir Kolmogorov.
+	In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), 
+	September 2004
+
+This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov
+at Siemens Corporate Research. To make it available for public use,
+it was later reimplemented by Vladimir Kolmogorov based on open publications.
+
+If you use this software for research purposes, you should cite
+the aforementioned paper in any resulting publication.
+
+Tested under windows, Visual C++ 6.0 compiler and unix (SunOS 5.8
+and RedHat Linux 7.0, GNU c++ compiler).
+
+##################################################################
+
+2. License.
+
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+##################################################################
+
+3. Graph representation.
+
+There are two versions of the algorithm using different
+graph representations (adjacency list and forward star).
+The former one uses more than twice as much memory as the
+latter one but is 10-20% faster.
+
+Memory allocation (assuming that all capacities are 'short' - 2 bytes):
+
+                 |   Nodes    |   Arcs
+------------------------------------------
+Adjacency list   | *24 bytes  | *14 bytes
+Forward star     | *28 bytes  |  6 bytes
+
+(* means that often it should be rounded up to be a multiple of 4
+- some compilers (e.g. Visual C++) seem to round up elements
+of arrays unless the are structures containing only char[].)
+
+Note that arcs are always added in pairs - in forward and reverse directions.
+Arcs between nodes and terminals (the source and the sink) are
+not stored as arcs, but rather as a part of nodes.
+
+The assumption for the forward star representation is that
+the maximum number of arcs per node (except the source
+and the sink) is much less than ARC_BLOCK_SIZE (1024 by default).
+
+Both versions have the same interface.
+
+##################################################################
+
+4. Example usage.
+
+This section shows how to use the library to compute
+a minimum cut on the following graph:
+
+		        SOURCE
+		       /       \
+		     1/         \2
+		     /      3    \
+		   node0 -----> node1
+		     |   <-----   |
+		     |      4     |
+		     \            /
+		     5\          /6
+		       \        /
+		          SINK
+
+///////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "graph.h"
+
+void main()
+{
+	Graph::node_id nodes[2];
+	Graph *g = new Graph();
+
+	nodes[0] = g -> add_node();
+	nodes[1] = g -> add_node();
+	g -> set_tweights(nodes[0], 1, 5);
+	g -> set_tweights(nodes[1], 2, 6);
+	g -> add_edge(nodes[0], nodes[1], 3, 4);
+
+	Graph::flowtype flow = g -> maxflow();
+
+	printf("Flow = %d\n", flow);
+	printf("Minimum cut:\n");
+	if (g->what_segment(nodes[0]) == Graph::SOURCE)
+		printf("node0 is in the SOURCE set\n");
+	else
+		printf("node0 is in the SINK set\n");
+	if (g->what_segment(nodes[1]) == Graph::SOURCE)
+		printf("node1 is in the SOURCE set\n");
+	else
+		printf("node1 is in the SINK set\n");
+
+	delete g;
+}
+
+///////////////////////////////////////////////////
diff --git a/package_bgs/ck/block.h b/package_bgs/ck/block.h
new file mode 100644
index 0000000000000000000000000000000000000000..a243ed1da41b47512afa8ddf9912a275b04cf76a
--- /dev/null
+++ b/package_bgs/ck/block.h
@@ -0,0 +1,286 @@
+/* block.h */
+/*
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/*
+	Template classes Block and DBlock
+	Implement adding and deleting items of the same type in blocks.
+
+	If there there are many items then using Block or DBlock
+	is more efficient than using 'new' and 'delete' both in terms
+	of memory and time since
+	(1) On some systems there is some minimum amount of memory
+	    that 'new' can allocate (e.g., 64), so if items are
+	    small that a lot of memory is wasted.
+	(2) 'new' and 'delete' are designed for items of varying size.
+	    If all items has the same size, then an algorithm for
+	    adding and deleting can be made more efficient.
+	(3) All Block and DBlock functions are inline, so there are
+	    no extra function calls.
+
+	Differences between Block and DBlock:
+	(1) DBlock allows both adding and deleting items,
+	    whereas Block allows only adding items.
+	(2) Block has an additional operation of scanning
+	    items added so far (in the order in which they were added).
+	(3) Block allows to allocate several consecutive
+	    items at a time, whereas DBlock can add only a single item.
+
+	Note that no constructors or destructors are called for items.
+
+	Example usage for items of type 'MyType':
+
+	///////////////////////////////////////////////////
+	#include "block.h"
+	#define BLOCK_SIZE 1024
+	typedef struct { int a, b; } MyType;
+	MyType *ptr, *array[10000];
+
+	...
+
+	Block<MyType> *block = new Block<MyType>(BLOCK_SIZE);
+
+	// adding items
+	for (int i=0; i<sizeof(array); i++)
+	{
+		ptr = block -> New();
+		ptr -> a = ptr -> b = rand();
+	}
+
+	// reading items
+	for (ptr=block->ScanFirst(); ptr; ptr=block->ScanNext())
+	{
+		printf("%d %d\n", ptr->a, ptr->b);
+	}
+
+	delete block;
+
+	...
+
+	DBlock<MyType> *dblock = new DBlock<MyType>(BLOCK_SIZE);
+	
+	// adding items
+	for (int i=0; i<sizeof(array); i++)
+	{
+		array[i] = dblock -> New();
+	}
+
+	// deleting items
+	for (int i=0; i<sizeof(array); i+=2)
+	{
+		dblock -> Delete(array[i]);
+	}
+
+	// adding items
+	for (int i=0; i<sizeof(array); i++)
+	{
+		array[i] = dblock -> New();
+	}
+
+	delete dblock;
+
+	///////////////////////////////////////////////////
+
+	Note that DBlock deletes items by marking them as
+	empty (i.e., by adding them to the list of free items),
+	so that this memory could be used for subsequently
+	added items. Thus, at each moment the memory allocated
+	is determined by the maximum number of items allocated
+	simultaneously at earlier moments. All memory is
+	deallocated only when the destructor is called.
+*/
+
+#ifndef __BLOCK_H__
+#define __BLOCK_H__
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+template <class Type> class Block
+{
+public:
+	/* Constructor. Arguments are the block size and
+	   (optionally) the pointer to the function which
+	   will be called if allocation failed; the message
+	   passed to this function is "Not enough memory!" */
+	Block(int size, void (*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; }
+
+	/* Destructor. Deallocates all items added so far */
+	~Block() { while (first) { block *next = first -> next; delete first; first = next; } }
+
+	/* Allocates 'num' consecutive items; returns pointer
+	   to the first item. 'num' cannot be greater than the
+	   block size since items must fit in one block */
+	Type *New(int num = 1)
+	{
+		Type *t;
+
+		if (!last || last->current + num > last->last)
+		{
+			if (last && last->next) last = last -> next;
+			else
+			{
+				block *next = (block *) new char [sizeof(block) + (block_size-1)*sizeof(Type)];
+                                if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); }
+				if (last) last -> next = next;
+				else first = next;
+				last = next;
+				last -> current = & ( last -> data[0] );
+				last -> last = last -> current + block_size;
+				last -> next = NULL;
+			}
+		}
+
+		t = last -> current;
+		last -> current += num;
+		return t;
+	}
+
+	/* Returns the first item (or NULL, if no items were added) */
+	Type *ScanFirst()
+	{
+		scan_current_block = first;
+		if (!scan_current_block) return NULL;
+		scan_current_data = & ( scan_current_block -> data[0] );
+		return scan_current_data ++;
+	}
+
+	/* Returns the next item (or NULL, if all items have been read)
+	   Can be called only if previous ScanFirst() or ScanNext()
+	   call returned not NULL. */
+	Type *ScanNext()
+	{
+		if (scan_current_data >= scan_current_block -> current)
+		{
+			scan_current_block = scan_current_block -> next;
+			if (!scan_current_block) return NULL;
+			scan_current_data = & ( scan_current_block -> data[0] );
+		}
+		return scan_current_data ++;
+	}
+
+	/* Marks all elements as empty */
+	void Reset()
+	{
+		block *b;
+		if (!first) return;
+		for (b=first; ; b=b->next)
+		{
+			b -> current = & ( b -> data[0] );
+			if (b == last) break;
+		}
+		last = first;
+	}
+
+/***********************************************************************/
+
+private:
+
+	typedef struct block_st
+	{
+		Type					*current, *last;
+		struct block_st			*next;
+		Type					data[1];
+	} block;
+
+	int		block_size;
+	block	*first;
+	block	*last;
+
+	block	*scan_current_block;
+	Type	*scan_current_data;
+
+	void	(*error_function)(char *);
+};
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+template <class Type> class DBlock
+{
+public:
+	/* Constructor. Arguments are the block size and
+	   (optionally) the pointer to the function which
+	   will be called if allocation failed; the message
+	   passed to this function is "Not enough memory!" */
+	DBlock(int size, void (*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; }
+
+	/* Destructor. Deallocates all items added so far */
+	~DBlock() { while (first) { block *next = first -> next; delete first; first = next; } }
+
+	/* Allocates one item */
+	Type *New()
+	{
+		block_item *item;
+
+		if (!first_free)
+		{
+			block *next = first;
+			first = (block *) new char [sizeof(block) + (block_size-1)*sizeof(block_item)];
+			if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); }
+			first_free = & (first -> data[0] );
+			for (item=first_free; item<first_free+block_size-1; item++)
+				item -> next_free = item + 1;
+			item -> next_free = NULL;
+			first -> next = next;
+		}
+
+		item = first_free;
+		first_free = item -> next_free;
+		return (Type *) item;
+	}
+
+	/* Deletes an item allocated previously */
+	void Delete(Type *t)
+	{
+		((block_item *) t) -> next_free = first_free;
+		first_free = (block_item *) t;
+	}
+
+/***********************************************************************/
+
+private:
+
+	typedef union block_item_st
+	{
+		Type			t;
+		block_item_st	*next_free;
+	} block_item;
+
+	typedef struct block_st
+	{
+		struct block_st			*next;
+		block_item				data[1];
+	} block;
+
+	int			block_size;
+	block		*first;
+	block_item	*first_free;
+
+	void	(*error_function)(char *);
+};
+
+
+#endif
+
diff --git a/package_bgs/ck/graph.cpp b/package_bgs/ck/graph.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb4cf9ff752514a402eedb9acf0ab061347395af
--- /dev/null
+++ b/package_bgs/ck/graph.cpp
@@ -0,0 +1,80 @@
+/* graph.cpp */
+/*
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#include <stdio.h>
+#include "graph.h"
+
+Graph::Graph(void (*err_function)(char *))
+{
+	error_function = err_function;
+	node_block = new Block<node>(NODE_BLOCK_SIZE, error_function);
+	arc_block  = new Block<arc>(NODE_BLOCK_SIZE, error_function);
+	flow = 0;
+}
+
+Graph::~Graph()
+{
+	delete node_block;
+	delete arc_block;
+}
+
+Graph::node_id Graph::add_node()
+{
+	node *i = node_block -> New();
+
+	i -> first = NULL;
+	i -> tr_cap = 0;
+
+	return (node_id) i;
+}
+
+void Graph::add_edge(node_id from, node_id to, captype cap, captype rev_cap)
+{
+	arc *a, *a_rev;
+
+	a = arc_block -> New(2);
+	a_rev = a + 1;
+
+	a -> sister = a_rev;
+	a_rev -> sister = a;
+	a -> next = ((node*)from) -> first;
+	((node*)from) -> first = a;
+	a_rev -> next = ((node*)to) -> first;
+	((node*)to) -> first = a_rev;
+	a -> head = (node*)to;
+	a_rev -> head = (node*)from;
+	a -> r_cap = cap;
+	a_rev -> r_cap = rev_cap;
+}
+
+void Graph::set_tweights(node_id i, captype cap_source, captype cap_sink)
+{
+	flow += (cap_source < cap_sink) ? cap_source : cap_sink;
+	((node*)i) -> tr_cap = cap_source - cap_sink;
+}
+
+void Graph::add_tweights(node_id i, captype cap_source, captype cap_sink)
+{
+	register captype delta = ((node*)i) -> tr_cap;
+	if (delta > 0) cap_source += delta;
+	else           cap_sink   -= delta;
+	flow += (cap_source < cap_sink) ? cap_source : cap_sink;
+	((node*)i) -> tr_cap = cap_source - cap_sink;
+}
diff --git a/package_bgs/ck/graph.h b/package_bgs/ck/graph.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdae5661b6b9a2ea56317a79e6c680503475f015
--- /dev/null
+++ b/package_bgs/ck/graph.h
@@ -0,0 +1,180 @@
+/* graph.h */
+/*
+	This software library implements the maxflow algorithm
+	described in
+
+		An Experimental Comparison of Min-Cut/Max-Flow Algorithms
+		for Energy Minimization in Vision.
+		Yuri Boykov and Vladimir Kolmogorov.
+		In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), 
+		September 2004
+
+	This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov
+	at Siemens Corporate Research. To make it available for public use,
+	it was later reimplemented by Vladimir Kolmogorov based on open publications.
+
+	If you use this software for research purposes, you should cite
+	the aforementioned paper in any resulting publication.
+*/
+	
+/*	
+	Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/*
+	For description, example usage, discussion of graph representation
+	and memory usage see README.TXT.
+*/
+
+#ifndef __GRAPH_H__
+#define __GRAPH_H__
+
+#include "block.h"
+
+/*
+	Nodes, arcs and pointers to nodes are
+	added in blocks for memory and time efficiency.
+	Below are numbers of items in blocks
+*/
+#define NODE_BLOCK_SIZE 512
+#define ARC_BLOCK_SIZE 1024
+#define NODEPTR_BLOCK_SIZE 128
+
+class Graph
+{
+public:
+	typedef enum
+	{
+		SOURCE	= 0,
+		SINK	= 1
+	} termtype; /* terminals */
+
+	/* Type of edge weights.
+	   Can be changed to char, int, float, double, ... */
+	typedef short captype;
+	/* Type of total flow */
+	typedef int flowtype;
+
+	typedef void * node_id;
+
+	/* interface functions */
+
+	/* Constructor. Optional argument is the pointer to the
+	   function which will be called if an error occurs;
+	   an error message is passed to this function. If this
+	   argument is omitted, exit(1) will be called. */
+	Graph(void (*err_function)(char *) = NULL);
+
+	/* Destructor */
+	~Graph();
+
+	/* Adds a node to the graph */
+	node_id add_node();
+
+	/* Adds a bidirectional edge between 'from' and 'to'
+	   with the weights 'cap' and 'rev_cap' */
+	void add_edge(node_id from, node_id to, captype cap, captype rev_cap);
+
+	/* Sets the weights of the edges 'SOURCE->i' and 'i->SINK'
+	   Can be called at most once for each node before any call to 'add_tweights'.
+	   Weights can be negative */
+	void set_tweights(node_id i, captype cap_source, captype cap_sink);
+
+	/* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights
+	   Can be called multiple times for each node.
+	   Weights can be negative */
+	void add_tweights(node_id i, captype cap_source, captype cap_sink);
+
+	/* After the maxflow is computed, this function returns to which
+	   segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */
+	termtype what_segment(node_id i);
+
+	/* Computes the maxflow. Can be called only once. */
+	flowtype maxflow();
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+	
+private:
+	/* internal variables and functions */
+
+	struct arc_st;
+
+	/* node structure */
+	typedef struct node_st
+	{
+		arc_st			*first;		/* first outcoming arc */
+
+		arc_st			*parent;	/* node's parent */
+		node_st			*next;		/* pointer to the next active node
+									   (or to itself if it is the last node in the list) */
+		int				TS;			/* timestamp showing when DIST was computed */
+		int				DIST;		/* distance to the terminal */
+		short			is_sink;	/* flag showing whether the node is in the source or in the sink tree */
+
+		captype			tr_cap;		/* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node
+									   otherwise         -tr_cap is residual capacity of the arc node->SINK */
+	} node;
+
+	/* arc structure */
+	typedef struct arc_st
+	{
+		node_st			*head;		/* node the arc points to */
+		arc_st			*next;		/* next arc with the same originating node */
+		arc_st			*sister;	/* reverse arc */
+
+		captype			r_cap;		/* residual capacity */
+	} arc;
+
+	/* 'pointer to node' structure */
+	typedef struct nodeptr_st
+	{
+		node_st			*ptr;
+		nodeptr_st		*next;
+	} nodeptr;
+
+	Block<node>			*node_block;
+	Block<arc>			*arc_block;
+	DBlock<nodeptr>		*nodeptr_block;
+
+	void	(*error_function)(char *);	/* this function is called if a error occurs,
+										   with a corresponding error message
+										   (or exit(1) is called if it's NULL) */
+
+	flowtype			flow;		/* total flow */
+
+/***********************************************************************/
+
+	node				*queue_first[2], *queue_last[2];	/* list of active nodes */
+	nodeptr				*orphan_first, *orphan_last;		/* list of pointers to orphans */
+	int					TIME;								/* monotonically increasing global counter */
+
+/***********************************************************************/
+
+	/* functions for processing active list */
+	void set_active(node *i);
+	node *next_active();
+
+	void maxflow_init();
+	void augment(arc *middle_arc);
+	void process_source_orphan(node *i);
+	void process_sink_orphan(node *i);
+};
+
+#endif
diff --git a/package_bgs/ck/maxflow.cpp b/package_bgs/ck/maxflow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8812a4a85d016049b70351c5aca936acca21868f
--- /dev/null
+++ b/package_bgs/ck/maxflow.cpp
@@ -0,0 +1,514 @@
+/* maxflow.cpp */
+/*
+    Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca).
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+#include <stdio.h>
+#include "graph.h"
+
+/*
+	special constants for node->parent
+*/
+#define TERMINAL ( (arc *) 1 )		/* to terminal */
+#define ORPHAN   ( (arc *) 2 )		/* orphan */
+
+#define INFINITE_D 1000000000		/* infinite distance to the terminal */
+
+/***********************************************************************/
+
+/*
+	Functions for processing active list.
+	i->next points to the next node in the list
+	(or to i, if i is the last node in the list).
+	If i->next is NULL iff i is not in the list.
+
+	There are two queues. Active nodes are added
+	to the end of the second queue and read from
+	the front of the first queue. If the first queue
+	is empty, it is replaced by the second queue
+	(and the second queue becomes empty).
+*/
+
+inline void Graph::set_active(node *i)
+{
+	if (!i->next)
+	{
+		/* it's not in the list yet */
+		if (queue_last[1]) queue_last[1] -> next = i;
+		else               queue_first[1]        = i;
+		queue_last[1] = i;
+		i -> next = i;
+	}
+}
+
+/*
+	Returns the next active node.
+	If it is connected to the sink, it stays in the list,
+	otherwise it is removed from the list
+*/
+inline Graph::node * Graph::next_active()
+{
+	node *i;
+
+	while ( 1 )
+	{
+		if (!(i=queue_first[0]))
+		{
+			queue_first[0] = i = queue_first[1];
+			queue_last[0]  = queue_last[1];
+			queue_first[1] = NULL;
+			queue_last[1]  = NULL;
+			if (!i) return NULL;
+		}
+
+		/* remove it from the active list */
+		if (i->next == i) queue_first[0] = queue_last[0] = NULL;
+		else              queue_first[0] = i -> next;
+		i -> next = NULL;
+
+		/* a node in the list is active iff it has a parent */
+		if (i->parent) return i;
+	}
+}
+
+/***********************************************************************/
+
+void Graph::maxflow_init()
+{
+	node *i;
+
+	queue_first[0] = queue_last[0] = NULL;
+	queue_first[1] = queue_last[1] = NULL;
+	orphan_first = NULL;
+
+	for (i=node_block->ScanFirst(); i; i=node_block->ScanNext())
+	{
+		i -> next = NULL;
+		i -> TS = 0;
+		if (i->tr_cap > 0)
+		{
+			/* i is connected to the source */
+			i -> is_sink = 0;
+			i -> parent = TERMINAL;
+			set_active(i);
+			i -> TS = 0;
+			i -> DIST = 1;
+		}
+		else if (i->tr_cap < 0)
+		{
+			/* i is connected to the sink */
+			i -> is_sink = 1;
+			i -> parent = TERMINAL;
+			set_active(i);
+			i -> TS = 0;
+			i -> DIST = 1;
+		}
+		else
+		{
+			i -> parent = NULL;
+		}
+	}
+	TIME = 0;
+}
+
+/***********************************************************************/
+
+void Graph::augment(arc *middle_arc)
+{
+	node *i;
+	arc *a;
+	captype bottleneck;
+	nodeptr *np;
+
+
+	/* 1. Finding bottleneck capacity */
+	/* 1a - the source tree */
+	bottleneck = middle_arc -> r_cap;
+	for (i=middle_arc->sister->head; ; i=a->head)
+	{
+		a = i -> parent;
+		if (a == TERMINAL) break;
+		if (bottleneck > a->sister->r_cap) bottleneck = a -> sister -> r_cap;
+	}
+	if (bottleneck > i->tr_cap) bottleneck = i -> tr_cap;
+	/* 1b - the sink tree */
+	for (i=middle_arc->head; ; i=a->head)
+	{
+		a = i -> parent;
+		if (a == TERMINAL) break;
+		if (bottleneck > a->r_cap) bottleneck = a -> r_cap;
+	}
+	if (bottleneck > - i->tr_cap) bottleneck = - i -> tr_cap;
+
+
+	/* 2. Augmenting */
+	/* 2a - the source tree */
+	middle_arc -> sister -> r_cap += bottleneck;
+	middle_arc -> r_cap -= bottleneck;
+	for (i=middle_arc->sister->head; ; i=a->head)
+	{
+		a = i -> parent;
+		if (a == TERMINAL) break;
+		a -> r_cap += bottleneck;
+		a -> sister -> r_cap -= bottleneck;
+		if (!a->sister->r_cap)
+		{
+			/* add i to the adoption list */
+			i -> parent = ORPHAN;
+			np = nodeptr_block -> New();
+			np -> ptr = i;
+			np -> next = orphan_first;
+			orphan_first = np;
+		}
+	}
+	i -> tr_cap -= bottleneck;
+	if (!i->tr_cap)
+	{
+		/* add i to the adoption list */
+		i -> parent = ORPHAN;
+		np = nodeptr_block -> New();
+		np -> ptr = i;
+		np -> next = orphan_first;
+		orphan_first = np;
+	}
+	/* 2b - the sink tree */
+	for (i=middle_arc->head; ; i=a->head)
+	{
+		a = i -> parent;
+		if (a == TERMINAL) break;
+		a -> sister -> r_cap += bottleneck;
+		a -> r_cap -= bottleneck;
+		if (!a->r_cap)
+		{
+			/* add i to the adoption list */
+			i -> parent = ORPHAN;
+			np = nodeptr_block -> New();
+			np -> ptr = i;
+			np -> next = orphan_first;
+			orphan_first = np;
+		}
+	}
+	i -> tr_cap += bottleneck;
+	if (!i->tr_cap)
+	{
+		/* add i to the adoption list */
+		i -> parent = ORPHAN;
+		np = nodeptr_block -> New();
+		np -> ptr = i;
+		np -> next = orphan_first;
+		orphan_first = np;
+	}
+
+
+	flow += bottleneck;
+}
+
+/***********************************************************************/
+
+void Graph::process_source_orphan(node *i)
+{
+	node *j;
+	arc *a0, *a0_min = NULL, *a;
+	nodeptr *np;
+	int d, d_min = INFINITE_D;
+
+	/* trying to find a new parent */
+	for (a0=i->first; a0; a0=a0->next)
+	if (a0->sister->r_cap)
+	{
+		j = a0 -> head;
+		if (!j->is_sink && (a=j->parent))
+		{
+			/* checking the origin of j */
+			d = 0;
+			while ( 1 )
+			{
+				if (j->TS == TIME)
+				{
+					d += j -> DIST;
+					break;
+				}
+				a = j -> parent;
+				d ++;
+				if (a==TERMINAL)
+				{
+					j -> TS = TIME;
+					j -> DIST = 1;
+					break;
+				}
+				if (a==ORPHAN) { d = INFINITE_D; break; }
+				j = a -> head;
+			}
+			if (d<INFINITE_D) /* j originates from the source - done */
+			{
+				if (d<d_min)
+				{
+					a0_min = a0;
+					d_min = d;
+				}
+				/* set marks along the path */
+				for (j=a0->head; j->TS!=TIME; j=j->parent->head)
+				{
+					j -> TS = TIME;
+					j -> DIST = d --;
+				}
+			}
+		}
+	}
+
+	if ((i->parent = a0_min))
+	{
+		i -> TS = TIME;
+		i -> DIST = d_min + 1;
+	}
+	else
+	{
+		/* no parent is found */
+		i -> TS = 0;
+
+		/* process neighbors */
+		for (a0=i->first; a0; a0=a0->next)
+		{
+			j = a0 -> head;
+			if (!j->is_sink && (a=j->parent))
+			{
+				if (a0->sister->r_cap) set_active(j);
+				if (a!=TERMINAL && a!=ORPHAN && a->head==i)
+				{
+					/* add j to the adoption list */
+					j -> parent = ORPHAN;
+					np = nodeptr_block -> New();
+					np -> ptr = j;
+					if (orphan_last) orphan_last -> next = np;
+					else             orphan_first        = np;
+					orphan_last = np;
+					np -> next = NULL;
+				}
+			}
+		}
+	}
+}
+
+void Graph::process_sink_orphan(node *i)
+{
+	node *j;
+	arc *a0, *a0_min = NULL, *a;
+	nodeptr *np;
+	int d, d_min = INFINITE_D;
+
+	/* trying to find a new parent */
+	for (a0=i->first; a0; a0=a0->next)
+	if (a0->r_cap)
+	{
+		j = a0 -> head;
+		if (j->is_sink && (a=j->parent))
+		{
+			/* checking the origin of j */
+			d = 0;
+			while ( 1 )
+			{
+				if (j->TS == TIME)
+				{
+					d += j -> DIST;
+					break;
+				}
+				a = j -> parent;
+				d ++;
+				if (a==TERMINAL)
+				{
+					j -> TS = TIME;
+					j -> DIST = 1;
+					break;
+				}
+				if (a==ORPHAN) { d = INFINITE_D; break; }
+				j = a -> head;
+			}
+			if (d<INFINITE_D) /* j originates from the sink - done */
+			{
+				if (d<d_min)
+				{
+					a0_min = a0;
+					d_min = d;
+				}
+				/* set marks along the path */
+				for (j=a0->head; j->TS!=TIME; j=j->parent->head)
+				{
+					j -> TS = TIME;
+					j -> DIST = d --;
+				}
+			}
+		}
+	}
+
+	if ((i->parent = a0_min))
+	{
+		i -> TS = TIME;
+		i -> DIST = d_min + 1;
+	}
+	else
+	{
+		/* no parent is found */
+		i -> TS = 0;
+
+		/* process neighbors */
+		for (a0=i->first; a0; a0=a0->next)
+		{
+			j = a0 -> head;
+			if (j->is_sink && (a=j->parent))
+			{
+				if (a0->r_cap) set_active(j);
+				if (a!=TERMINAL && a!=ORPHAN && a->head==i)
+				{
+					/* add j to the adoption list */
+					j -> parent = ORPHAN;
+					np = nodeptr_block -> New();
+					np -> ptr = j;
+					if (orphan_last) orphan_last -> next = np;
+					else             orphan_first        = np;
+					orphan_last = np;
+					np -> next = NULL;
+				}
+			}
+		}
+	}
+}
+
+/***********************************************************************/
+
+Graph::flowtype Graph::maxflow()
+{
+	node *i, *j, *current_node = NULL;
+	arc *a;
+	nodeptr *np, *np_next;
+
+	maxflow_init();
+	nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
+
+	while ( 1 )
+	{
+		if ((i=current_node))
+		{
+			i -> next = NULL; /* remove active flag */
+			if (!i->parent) i = NULL;
+		}
+		if (!i)
+		{
+			if (!(i = next_active())) break;
+		}
+
+		/* growth */
+		if (!i->is_sink)
+		{
+			/* grow source tree */
+			for (a=i->first; a; a=a->next)
+			if (a->r_cap)
+			{
+				j = a -> head;
+				if (!j->parent)
+				{
+					j -> is_sink = 0;
+					j -> parent = a -> sister;
+					j -> TS = i -> TS;
+					j -> DIST = i -> DIST + 1;
+					set_active(j);
+				}
+				else if (j->is_sink) break;
+				else if (j->TS <= i->TS &&
+				         j->DIST > i->DIST)
+				{
+					/* heuristic - trying to make the distance from j to the source shorter */
+					j -> parent = a -> sister;
+					j -> TS = i -> TS;
+					j -> DIST = i -> DIST + 1;
+				}
+			}
+		}
+		else
+		{
+			/* grow sink tree */
+			for (a=i->first; a; a=a->next)
+			if (a->sister->r_cap)
+			{
+				j = a -> head;
+				if (!j->parent)
+				{
+					j -> is_sink = 1;
+					j -> parent = a -> sister;
+					j -> TS = i -> TS;
+					j -> DIST = i -> DIST + 1;
+					set_active(j);
+				}
+				else if (!j->is_sink) { a = a -> sister; break; }
+				else if (j->TS <= i->TS &&
+				         j->DIST > i->DIST)
+				{
+					/* heuristic - trying to make the distance from j to the sink shorter */
+					j -> parent = a -> sister;
+					j -> TS = i -> TS;
+					j -> DIST = i -> DIST + 1;
+				}
+			}
+		}
+
+		TIME ++;
+
+		if (a)
+		{
+			i -> next = i; /* set active flag */
+			current_node = i;
+
+			/* augmentation */
+			augment(a);
+			/* augmentation end */
+
+			/* adoption */
+			while ((np=orphan_first))
+			{
+				np_next = np -> next;
+				np -> next = NULL;
+
+				while ((np=orphan_first))
+				{
+					orphan_first = np -> next;
+					i = np -> ptr;
+					nodeptr_block -> Delete(np);
+					if (!orphan_first) orphan_last = NULL;
+					if (i->is_sink) process_sink_orphan(i);
+					else            process_source_orphan(i);
+				}
+
+				orphan_first = np_next;
+			}
+			/* adoption end */
+		}
+		else current_node = NULL;
+	}
+
+	delete nodeptr_block;
+
+	return flow;
+}
+
+/***********************************************************************/
+
+Graph::termtype Graph::what_segment(node_id i)
+{
+	if (((node*)i)->parent && !((node*)i)->is_sink) return SOURCE;
+	return SINK;
+}
+
diff --git a/package_bgs/db/IndependentMultimodalBGS.cpp b/package_bgs/db/IndependentMultimodalBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c05ee5cb0684117637cebfa23d4989c7177d92a6
--- /dev/null
+++ b/package_bgs/db/IndependentMultimodalBGS.cpp
@@ -0,0 +1,54 @@
+#include "IndependentMultimodalBGS.h"
+
+IndependentMultimodalBGS::IndependentMultimodalBGS() : firstTime(true), fps(10), showOutput(true){
+  pIMBS = new BackgroundSubtractorIMBS(fps);
+}
+IndependentMultimodalBGS::~IndependentMultimodalBGS(){
+  delete pIMBS;
+}
+
+void IndependentMultimodalBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if (firstTime)
+    saveConfig();
+
+  //get the fgmask and update the background model
+  pIMBS->apply(img_input, img_foreground);
+  
+  //get background image
+  pIMBS->getBackgroundImage(img_background);
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+
+  if (showOutput)
+  {
+    cv::imshow("IMBS FG", img_foreground);
+    cv::imshow("IMBS BG", img_background);
+  }
+
+  firstTime = false;
+}
+
+void IndependentMultimodalBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/IndependentMultimodalBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void IndependentMultimodalBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/IndependentMultimodalBGS.xml", 0, CV_STORAGE_READ);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/db/IndependentMultimodalBGS.h b/package_bgs/db/IndependentMultimodalBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..b6f9a5de9abd15441a2ad7a1127427f45df07628
--- /dev/null
+++ b/package_bgs/db/IndependentMultimodalBGS.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <cv.h>
+#include <highgui.h>
+
+#include "imbs.hpp"
+
+#include "../IBGS.h"
+
+class IndependentMultimodalBGS : public IBGS
+{
+private:
+  BackgroundSubtractorIMBS* pIMBS;
+  int fps;
+  bool firstTime;
+  cv::Mat img_foreground;
+  cv::Mat img_background;
+  bool showOutput;
+  
+public:
+  IndependentMultimodalBGS();
+  ~IndependentMultimodalBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/db/imbs.cpp b/package_bgs/db/imbs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..715d699c117c4dab3c41a270d8f28791e31c8852
--- /dev/null
+++ b/package_bgs/db/imbs.cpp
@@ -0,0 +1,748 @@
+/*
+*  IMBS Background Subtraction Library 
+*
+*  This file imbs.hpp contains the C++ OpenCV based implementation for
+*  IMBS algorithm described in
+*  D. D. Bloisi and L. Iocchi
+*  "Independent Multimodal Background Subtraction"
+*  In Proc. of the Third Int. Conf. on Computational Modeling of Objects
+*  Presented in Images: Fundamentals, Methods and Applications, pp. 39-44, 2012.
+*  Please, cite the above paper if you use IMBS.
+*  
+*  This software is provided without any warranty about its usability. 
+*  It is for educational purposes and should be regarded as such.
+*
+*  Written by Domenico D. Bloisi
+*
+*  Please, report suggestions/comments/bugs to
+*  domenico.bloisi@gmail.com
+*
+*/
+
+#include "imbs.hpp"
+
+using namespace std;
+using namespace cv;
+
+BackgroundSubtractorIMBS::BackgroundSubtractorIMBS()
+{
+  fps = 0.;
+  fgThreshold = 15;
+  associationThreshold = 5;
+  samplingPeriod = 250.;//500.ms
+  minBinHeight = 2;
+  numSamples = 10; //30
+  alpha = 0.65;
+  beta = 1.15;
+  tau_s = 60.;
+  tau_h = 40.;
+  minArea = 30.;
+  persistencePeriod = samplingPeriod*numSamples/3.;//ms
+
+  initial_tick_count = (double)getTickCount();
+
+  //morphological Opening and closing
+  morphologicalFiltering = false;
+}
+
+BackgroundSubtractorIMBS::BackgroundSubtractorIMBS(
+  double fps,
+  unsigned int fgThreshold,
+  unsigned int associationThreshold,
+  double samplingPeriod,
+  unsigned int minBinHeight,
+  unsigned int numSamples,
+  double alpha,
+  double beta,
+  double tau_s,
+  double tau_h,
+  double minArea,
+  double persistencePeriod,
+  bool morphologicalFiltering)
+{
+  this->fps = fps;
+  this->fgThreshold = fgThreshold;
+  this->persistencePeriod = persistencePeriod;
+  if(minBinHeight <= 1){
+    this->minBinHeight = 1;
+  }
+  else {
+    this->minBinHeight = minBinHeight;
+  }
+  this->associationThreshold = associationThreshold;
+  this->samplingPeriod = samplingPeriod;//ms
+  this->minBinHeight = minBinHeight;
+  this->numSamples = numSamples;
+  this->alpha = alpha;
+  this->beta = beta;
+  this->tau_s = tau_s;
+  this->tau_h = tau_h;
+  this->minArea = minArea;
+
+  if(fps == 0.)
+    initial_tick_count = (double)getTickCount();
+  else
+    initial_tick_count = 0;
+
+  //morphological Opening and closing
+  this->morphologicalFiltering = morphologicalFiltering;
+}
+
+BackgroundSubtractorIMBS::~BackgroundSubtractorIMBS()
+{
+  delete[] bgBins;
+  delete[] bgModel;
+  delete[] persistenceMap;
+}
+
+void BackgroundSubtractorIMBS::initialize(Size frameSize, int frameType)
+{
+  /*cout << "INPUT: WIDTH " << frameSize.width << "  HEIGHT " << frameSize.height <<
+    "  FPS " << fps << endl;
+  cout << endl;*/
+
+  this->frameSize = frameSize;
+  this->frameType = frameType;
+  this->numPixels = frameSize.width*frameSize.height;
+
+  persistenceMap = new unsigned int[numPixels];
+  for(int i = 0; i < numPixels; i++) {
+    persistenceMap[i] = 0;
+  }
+
+  bgBins = new Bins[numPixels];
+  bgModel = new BgModel[numPixels];
+  maxBgBins = numSamples / minBinHeight;
+
+  timestamp = 0.;//ms
+  prev_timestamp = 0.;//ms
+  prev_bg_frame_time = 0;
+  bg_frame_counter = 0;
+  bg_reset = false;
+  prev_area = 0;
+  sudden_change = false;
+
+  SHADOW_LABEL = 80;
+  PERSISTENCE_LABEL = 180;
+  FOREGROUND_LABEL = 255;
+
+  fgmask.create(frameSize, CV_8UC1);
+  fgfiltered.create(frameSize, CV_8UC1);
+  persistenceImage = Mat::zeros(frameSize, CV_8UC1);
+  bgSample.create(frameSize, CV_8UC3);
+  bgImage = Mat::zeros(frameSize, CV_8UC3);
+
+  //initial message to be shown until the first fg mask is computed
+  initialMsgGray = Mat::zeros(frameSize, CV_8UC1);
+  putText(initialMsgGray, "Creating", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255));
+  putText(initialMsgGray, "initial", Point(10,40), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255));
+  putText(initialMsgGray, "background...", Point(10,60), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255));
+
+  initialMsgRGB = Mat::zeros(frameSize, CV_8UC3);
+  putText(initialMsgRGB, "Creating", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255));
+  putText(initialMsgRGB, "initial", Point(10,40), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255));
+  putText(initialMsgRGB, "background...", Point(10,60), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255));
+
+  if(minBinHeight <= 1){
+    minBinHeight = 1;
+  }
+
+  for(unsigned int p = 0; p < numPixels; ++p)
+  {
+    bgBins[p].binValues = new Vec3b[numSamples];
+    bgBins[p].binHeights = new uchar[numSamples];
+    bgBins[p].isFg = new bool[numSamples];
+
+    bgModel[p].values = new Vec3b[maxBgBins];
+    bgModel[p].isValid = new bool[maxBgBins];
+    bgModel[p].isValid[0] = false;
+    bgModel[p].isFg = new bool[maxBgBins];
+    bgModel[p].counter = new uchar[maxBgBins];
+  }
+}
+
+void BackgroundSubtractorIMBS::apply(InputArray _frame, OutputArray _fgmask, double learningRate)
+{
+  frame = _frame.getMat();
+
+  CV_Assert(frame.depth() == CV_8U);
+  CV_Assert(frame.channels() == 3);
+
+  bool needToInitialize = nframes == 0 || frame.type() != frameType;
+  if( needToInitialize ) {
+    initialize(frame.size(), frame.type());
+  }
+
+  _fgmask.create(frameSize, CV_8UC1);
+  fgmask = _fgmask.getMat();
+  fgmask = Scalar(0);
+
+  //get current time
+  prev_timestamp = timestamp;
+  if(fps == 0.) {
+    timestamp = getTimestamp();//ms
+  }
+  else {
+    timestamp += 1000./fps;//ms
+  }
+
+  //check for global changes
+  if(sudden_change) {
+    changeBg();
+  }
+
+  //wait for the first model to be generated
+  if(bgModel[0].isValid[0]) {
+    getFg();    	
+    hsvSuppression();
+    filterFg();
+  }	
+  //update the bg model
+  updateBg();
+
+  //show an initial message if the first bg is not yet ready
+  if(!bgModel[0].isValid[0]) {
+    initialMsgGray.copyTo(fgmask);
+    initialMsgRGB.copyTo(bgImage);
+  }
+  ++nframes;
+}
+
+void BackgroundSubtractorIMBS::updateBg() {
+  if(bg_reset) {
+    if(bg_frame_counter > numSamples - 1) {
+      bg_frame_counter = numSamples - 1;
+    }
+  }
+
+  if(prev_bg_frame_time > timestamp) {
+    prev_bg_frame_time = timestamp;
+  }
+
+  if(bg_frame_counter == numSamples - 1) {
+    createBg(bg_frame_counter);
+    bg_frame_counter = 0;
+  }
+  else { //bg_frame_counter < (numSamples - 1)
+
+    if((timestamp - prev_bg_frame_time) >= samplingPeriod)
+    {
+      //get a new sample for creating the bg model
+      prev_bg_frame_time = timestamp;
+      frame.copyTo(bgSample);
+      createBg(bg_frame_counter);
+      bg_frame_counter++;
+    }
+  }
+}
+
+double BackgroundSubtractorIMBS::getTimestamp() {
+  return ((double)getTickCount() - initial_tick_count)*1000./getTickFrequency();
+}
+
+void BackgroundSubtractorIMBS::hsvSuppression() {
+
+  uchar h_i, s_i, v_i;
+  uchar h_b, s_b, v_b;
+  float h_diff, s_diff, v_ratio;
+
+  Mat bgrPixel(cv::Size(1, 1), CV_8UC3);
+
+  vector<Mat> imHSV;
+  cv::split(convertImageRGBtoHSV(frame), imHSV);
+
+  for(unsigned int p = 0; p < numPixels; ++p) {
+    if(fgmask.data[p]) {
+
+      h_i = imHSV[0].data[p];
+      s_i = imHSV[1].data[p];
+      v_i = imHSV[2].data[p];
+
+      for(unsigned int n = 0; n < maxBgBins; ++n) {
+        if(!bgModel[p].isValid[n]) {
+          break;
+        }
+
+        if(bgModel[p].isFg[n]) {
+          continue;
+        }
+
+        bgrPixel.at<cv::Vec3b>(0,0) = bgModel[p].values[n];
+
+        cv::Mat hsvPixel = convertImageRGBtoHSV(bgrPixel);
+
+        h_b = hsvPixel.at<cv::Vec3b>(0,0)[0];
+        s_b = hsvPixel.at<cv::Vec3b>(0,0)[1];
+        v_b = hsvPixel.at<cv::Vec3b>(0,0)[2];
+
+        v_ratio = (float)v_i / (float)v_b;
+        s_diff = std::abs(s_i - s_b);
+        h_diff = std::min( std::abs(h_i - h_b), 255 - std::abs(h_i - h_b));
+
+        if(	h_diff <= tau_h &&
+          s_diff <= tau_s &&
+          v_ratio >= alpha &&
+          v_ratio < beta)
+        {
+          fgmask.data[p] = SHADOW_LABEL;
+          break;
+        }
+      }//for
+    }//if
+  }//numPixels
+}
+
+void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) {
+  if(!bgSample.data) {
+    //cerr << "createBg -- an error occurred: " <<
+    //		" unable to retrieve frame no. " << bg_sample_number << endl;
+
+    //TODO vedere gestione errori
+    abort();
+  }
+  //aux variable
+  Vec3b currentPixel;
+  //split bgSample in channels
+  cv::split(bgSample, bgSampleBGR);
+  //create a statistical model for each pixel (a set of bins of variable size)
+  for(unsigned int p = 0; p < numPixels; ++p) {
+    //create an initial bin for each pixel from the first sample (bg_sample_number = 0)
+    if(bg_sample_number == 0) {
+      for(int k = 0; k < 3; ++k) {
+        bgBins[p].binValues[0][k] = bgSampleBGR[k].data[p];
+      }
+      bgBins[p].binHeights[0] = 1;
+      for(unsigned int s = 1; s < numSamples; ++s)	{
+        bgBins[p].binHeights[s] = 0;
+      }
+      //if the sample pixel is from foreground keep track of that situation
+      if(fgmask.data[p] == FOREGROUND_LABEL) {
+        bgBins[p].isFg[0] = true;
+      }
+      else {
+        bgBins[p].isFg[0] = false;
+      }
+    }//if(bg_sample_number == 0)
+    else { //bg_sample_number > 0
+      for(int k = 0; k < 3; ++k) {
+        currentPixel[k] = bgSampleBGR[k].data[p];
+      }
+      int den = 0;
+      for(unsigned int s = 0; s < bg_sample_number; ++s) {
+        //try to associate the current pixel values to an existing bin
+        if( std::abs(currentPixel[2] - bgBins[p].binValues[s][2]) <= associationThreshold &&
+          std::abs(currentPixel[1] - bgBins[p].binValues[s][1]) <= associationThreshold &&
+          std::abs(currentPixel[0] - bgBins[p].binValues[s][0]) <= associationThreshold )
+        {
+          den = (bgBins[p].binHeights[s] + 1);
+          for(int k = 0; k < 3; ++k) {
+            bgBins[p].binValues[s][k] =
+              (bgBins[p].binValues[s][k] * bgBins[p].binHeights[s] + currentPixel[k]) / den;
+          }
+          bgBins[p].binHeights[s]++; //increment the height of the bin
+          if(fgmask.data[p] == FOREGROUND_LABEL) {
+            bgBins[p].isFg[s] = true;
+          }
+          break;
+        }
+        //if the association is not possible, create a new bin
+        else if(bgBins[p].binHeights[s] == 0)	{
+          bgBins[p].binValues[s] = currentPixel;
+          bgBins[p].binHeights[s]++;
+          if(fgmask.data[p] == FOREGROUND_LABEL) {
+            bgBins[p].isFg[s] = true;
+          }
+          else {
+            bgBins[p].isFg[s] = false;
+          }
+          break;
+        }
+        else continue;
+      }//for(unsigned int s = 0; s <= bg_sample_number; ++s)
+
+      //if all samples have been processed
+      //it is time to compute the fg mask
+      if(bg_sample_number == (numSamples - 1)) {
+        unsigned int index = 0;
+        int max_height = -1;
+        for(unsigned int s = 0; s < numSamples; ++s){
+          if(bgBins[p].binHeights[s] == 0) {
+            bgModel[p].isValid[index] = false;
+            break;
+          }
+          if(index == maxBgBins) {
+            break;
+          }
+          else if(bgBins[p].binHeights[s] >= minBinHeight) {
+            if(fgmask.data[p] == PERSISTENCE_LABEL) {
+              for(unsigned int n = 0; n < maxBgBins; n++) {
+                if(!bgModel[p].isValid[n]) {
+                  break;
+                }
+                unsigned int d = std::max((int)std::abs(bgModel[p].values[n][0] - bgBins[p].binValues[s][0]),
+                  std::abs(bgModel[p].values[n][1] - bgBins[p].binValues[s][1]) );
+                d = std::max((int)d, std::abs(bgModel[p].values[n][2] - bgBins[p].binValues[s][2]) );
+                if(d < fgThreshold){
+                  bgModel[p].isFg[n] = false;
+                  bgBins[p].isFg[s] = false;
+                }
+              }
+            }
+
+            if(bgBins[p].binHeights[s] > max_height) {
+              max_height = bgBins[p].binHeights[s];
+
+              for(int k = 0; k < 3; ++k) {
+                bgModel[p].values[index][k] = bgModel[p].values[0][k];
+              }
+              bgModel[p].isValid[index] = true;
+              bgModel[p].isFg[index] = bgModel[p].isFg[0];
+              bgModel[p].counter[index] = bgModel[p].counter[0];
+
+              for(int k = 0; k < 3; ++k) {
+                bgModel[p].values[0][k] = bgBins[p].binValues[s][k];
+              }
+              bgModel[p].isValid[0] = true;
+              bgModel[p].isFg[0] = bgBins[p].isFg[s];
+              bgModel[p].counter[0] = bgBins[p].binHeights[s];
+            }
+            else {
+              for(int k = 0; k < 3; ++k) {
+                bgModel[p].values[index][k] = bgBins[p].binValues[s][k];
+              }
+              bgModel[p].isValid[index] = true;
+              bgModel[p].isFg[index] = bgBins[p].isFg[s];
+              bgModel[p].counter[index] = bgBins[p].binHeights[s];
+            }
+            ++index;
+          }
+        } //for all numSamples
+      }//bg_sample_number == (numSamples - 1)
+    }//else --> if(frame_number == 0)
+  }//numPixels
+
+  if(bg_sample_number == (numSamples - 1)) {
+    //std::cout << "new bg created" << std::endl;		
+    persistenceImage = Scalar(0);
+
+    bg_reset = false;
+    if(sudden_change) {
+      numSamples *= 3.;
+      samplingPeriod *= 2.;
+      sudden_change = false;
+    }
+
+    for(int i = 0; i < numPixels; i++) {
+      persistenceMap[i] = 0;
+    }
+
+    unsigned int p = 0;
+    for(int i = 0; i < bgImage.rows; ++i) {
+      for(int j = 0; j < bgImage.cols; ++j, ++p) {
+        bgImage.at<cv::Vec3b>(i,j) = bgModel[p].values[0];
+      }
+    }
+  }
+}
+
+void BackgroundSubtractorIMBS::getFg() {
+  fgmask = Scalar(0);
+  cv::split(frame, frameBGR);
+
+  bool isFg = true;
+  bool conditionalUpdated = false;
+  unsigned int d = 0;
+  for(unsigned int p = 0; p < numPixels; ++p) {
+    isFg = true;
+    conditionalUpdated = false;
+    d = 0;
+    for(unsigned int n = 0; n < maxBgBins; ++n) {
+      if(!bgModel[p].isValid[n]) {
+        if(n == 0) {
+          isFg = false;
+        }
+        break;
+      }
+      else { //the model is valid
+        d = std::max(
+          (int)std::abs(bgModel[p].values[n][0] - frameBGR[0].data[p]),
+          std::abs(bgModel[p].values[n][1] - frameBGR[1].data[p]) );
+        d = std::max(
+          (int)d, std::abs(bgModel[p].values[n][2] - frameBGR[2].data[p]) );
+        if(d < fgThreshold){
+          //check if it is a potential background pixel
+          //from stationary object
+          if(bgModel[p].isFg[n]) {
+            conditionalUpdated = true;
+            break;
+          }
+          else {
+            isFg = false;
+            persistenceMap[p] = 0;
+          }
+        }
+      }
+    }
+    if(isFg) {
+      if(conditionalUpdated) {
+        fgmask.data[p] = PERSISTENCE_LABEL;
+        persistenceMap[p] += (timestamp - prev_timestamp);
+        if(persistenceMap[p] > persistencePeriod) {
+          for(unsigned int n = 0; n < maxBgBins; ++n) {
+            if(!bgModel[p].isValid[n]) {
+              break;
+            }
+            bgModel[p].isFg[n] = false;
+          }
+        }
+      }
+      else {
+        fgmask.data[p] = FOREGROUND_LABEL;
+        persistenceMap[p] = 0;
+      }
+    }
+  }
+}
+
+void BackgroundSubtractorIMBS::areaThresholding()
+{
+  double maxArea = 0.6 * numPixels;
+
+  std::vector < std::vector<Point> > contours;
+  Mat tmpBinaryImage = fgfiltered.clone();
+  findContours(tmpBinaryImage, contours, RETR_LIST, CHAIN_APPROX_NONE);
+
+  tmpBinaryImage = Scalar(0);
+
+  for (size_t contourIdx = 0; contourIdx < contours.size(); ++contourIdx)
+  {
+    Moments moms = moments(Mat(contours[contourIdx]));
+    double area = moms.m00;
+    if (area < minArea || area >= maxArea)
+      continue;
+    else {
+      drawContours( tmpBinaryImage, contours, contourIdx, Scalar(255), CV_FILLED );
+    }
+  }	
+  for(int i = 0; i < fgfiltered.rows; ++i) {
+    for(int j = 0; j < fgfiltered.cols; ++j) {
+      if(!tmpBinaryImage.at<uchar>(i,j)) {
+        fgfiltered.at<uchar>(i,j) = 0;
+      }
+    }
+  }
+}
+
+// Create a HSV image from the RGB image using the full 8-bits, since OpenCV only allows Hues up to 180 instead of 255.
+// ref: "http://cs.haifa.ac.il/hagit/courses/ist/Lectures/Demos/ColorApplet2/t_convert.html"
+// Remember to free the generated HSV image.
+Mat BackgroundSubtractorIMBS::convertImageRGBtoHSV(const Mat& imageRGB)
+{
+  float fR, fG, fB;
+  float fH, fS, fV;
+  const float FLOAT_TO_BYTE = 255.0f;
+  const float BYTE_TO_FLOAT = 1.0f / FLOAT_TO_BYTE;
+
+  // Create a blank HSV image
+  Mat imageHSV(imageRGB.size(), CV_8UC3);
+  //if (!imageHSV || imageRGB->depth != 8 || imageRGB->nChannels != 3) {
+  //printf("ERROR in convertImageRGBtoHSV()! Bad input image.\n");
+  //exit(1);
+  //}
+
+  int h = imageRGB.rows;		// Pixel height.
+  int w = imageRGB.cols;		// Pixel width.
+  //int rowSizeRGB = imageRGB->widthStep;	// Size of row in bytes, including extra padding.
+  //char *imRGB = imageRGB->imageData;	// Pointer to the start of the image pixels.
+  //int rowSizeHSV = imageHSV->widthStep;	// Size of row in bytes, including extra padding.
+  //char *imHSV = imageHSV->imageData;	// Pointer to the start of the image pixels.
+  for (int y = 0; y < h; ++y) {
+    for (int x = 0; x < w; ++x) {
+      // Get the RGB pixel components. NOTE that OpenCV stores RGB pixels in B,G,R order.
+      //uchar *pRGB = (uchar*)(imRGB + y*rowSizeRGB + x*3);
+      int bB = imageRGB.at<Vec3b>(y,x)[0]; //*(uchar*)(pRGB+0);	// Blue component
+      int bG = imageRGB.at<Vec3b>(y,x)[1]; //*(uchar*)(pRGB+1);	// Green component
+      int bR = imageRGB.at<Vec3b>(y,x)[2]; //*(uchar*)(pRGB+2);	// Red component
+
+      // Convert from 8-bit integers to floats.
+      fR = bR * BYTE_TO_FLOAT;
+      fG = bG * BYTE_TO_FLOAT;
+      fB = bB * BYTE_TO_FLOAT;
+
+      // Convert from RGB to HSV, using float ranges 0.0 to 1.0.
+      float fDelta;
+      float fMin, fMax;
+      int iMax;
+      // Get the min and max, but use integer comparisons for slight speedup.
+      if (bB < bG) {
+        if (bB < bR) {
+          fMin = fB;
+          if (bR > bG) {
+            iMax = bR;
+            fMax = fR;
+          }
+          else {
+            iMax = bG;
+            fMax = fG;
+          }
+        }
+        else {
+          fMin = fR;
+          fMax = fG;
+          iMax = bG;
+        }
+      }
+      else {
+        if (bG < bR) {
+          fMin = fG;
+          if (bB > bR) {
+            fMax = fB;
+            iMax = bB;
+          }
+          else {
+            fMax = fR;
+            iMax = bR;
+          }
+        }
+        else {
+          fMin = fR;
+          fMax = fB;
+          iMax = bB;
+        }
+      }
+      fDelta = fMax - fMin;
+      fV = fMax;				// Value (Brightness).
+      if (iMax != 0) {			// Make sure its not pure black.
+        fS = fDelta / fMax;		// Saturation.
+        float ANGLE_TO_UNIT = 1.0f / (6.0f * fDelta);	// Make the Hues between 0.0 to 1.0 instead of 6.0
+        if (iMax == bR) {		// between yellow and magenta.
+          fH = (fG - fB) * ANGLE_TO_UNIT;
+        }
+        else if (iMax == bG) {		// between cyan and yellow.
+          fH = (2.0f/6.0f) + ( fB - fR ) * ANGLE_TO_UNIT;
+        }
+        else {				// between magenta and cyan.
+          fH = (4.0f/6.0f) + ( fR - fG ) * ANGLE_TO_UNIT;
+        }
+        // Wrap outlier Hues around the circle.
+        if (fH < 0.0f)
+          fH += 1.0f;
+        if (fH >= 1.0f)
+          fH -= 1.0f;
+      }
+      else {
+        // color is pure Black.
+        fS = 0;
+        fH = 0;	// undefined hue
+      }
+
+      // Convert from floats to 8-bit integers.
+      int bH = (int)(0.5f + fH * 255.0f);
+      int bS = (int)(0.5f + fS * 255.0f);
+      int bV = (int)(0.5f + fV * 255.0f);
+
+      // Clip the values to make sure it fits within the 8bits.
+      if (bH > 255)
+        bH = 255;
+      if (bH < 0)
+        bH = 0;
+      if (bS > 255)
+        bS = 255;
+      if (bS < 0)
+        bS = 0;
+      if (bV > 255)
+        bV = 255;
+      if (bV < 0)
+        bV = 0;
+
+      // Set the HSV pixel components.
+      imageHSV.at<Vec3b>(y, x)[0] = bH;		// H component
+      imageHSV.at<Vec3b>(y, x)[1] = bS;		// S component
+      imageHSV.at<Vec3b>(y, x)[2] = bV;		// V component
+    }
+  }
+  return imageHSV;
+}
+
+void BackgroundSubtractorIMBS::getBackgroundImage(OutputArray backgroundImage) const
+{
+  bgImage.copyTo(backgroundImage);        
+}
+
+void BackgroundSubtractorIMBS::filterFg() {
+
+  unsigned int cnt = 0;
+  for(unsigned int p = 0; p < numPixels; ++p) {
+    if(fgmask.data[p] == (uchar)255) {
+      fgfiltered.data[p] = 255;
+      cnt++;
+    }
+    else {
+      fgfiltered.data[p] = 0;
+    }
+  }
+
+  if(cnt > numPixels*0.5) {
+    sudden_change = true;
+  }
+
+  if(morphologicalFiltering) {
+    cv::Mat element3(3,3,CV_8U,cv::Scalar(1));
+    cv::morphologyEx(fgfiltered, fgfiltered, cv::MORPH_OPEN, element3);
+    cv::morphologyEx(fgfiltered, fgfiltered, cv::MORPH_CLOSE, element3);
+  }
+
+  areaThresholding();
+
+  for(unsigned int p = 0; p < numPixels; ++p) {
+    if(fgmask.data[p] == PERSISTENCE_LABEL) {
+      fgfiltered.data[p] = PERSISTENCE_LABEL;
+    }
+    else if(fgmask.data[p] == SHADOW_LABEL) {
+      fgfiltered.data[p] = SHADOW_LABEL;
+    }
+  }
+
+  fgfiltered.copyTo(fgmask);
+}
+
+void BackgroundSubtractorIMBS::changeBg() {
+
+  std::cout << "\n\n\n\nWARNING: changeBg\n\n\n\n\n" << std::endl;
+
+  //samplingPeriod /= 2.;
+  //numSamples /= 2.;
+  //bg_reset = true;
+  //cout << "qua" << endl;
+
+  if(!bg_reset) {
+    numSamples /= 3.;
+    samplingPeriod /= 2.;
+    bg_frame_counter = 0;
+    bg_reset = true;
+  }
+}
+
+void BackgroundSubtractorIMBS::getBgModel(BgModel bgModel_copy[], int size) {
+  if(size != numPixels) {
+    return;
+  }
+  for(int i = 0; i < numPixels; ++i){
+    bgModel_copy[i].values = new Vec3b[maxBgBins];
+    bgModel_copy[i].isValid = new bool[maxBgBins];
+    bgModel_copy[i].isValid[0] = false;
+    bgModel_copy[i].isFg = new bool[maxBgBins];
+    bgModel_copy[i].counter = new uchar[maxBgBins];
+  }
+  for(unsigned int p = 0; p < numPixels; ++p) {
+    for(unsigned int n = 0; n < maxBgBins; ++n) {
+      if(!bgModel[p].isValid[n]) {
+        break;
+      }
+      bgModel_copy[p].values[n] = bgModel[p].values[n];
+      bgModel_copy[p].isValid[n] = bgModel[p].isValid[n];
+      bgModel_copy[p].isFg[n] = bgModel[p].isFg[n];
+      bgModel_copy[p].counter[n] = bgModel[p].counter[n];
+    }
+  }
+}
diff --git a/package_bgs/db/imbs.hpp b/package_bgs/db/imbs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd7faf17ce44bb26a5345984b5768df1a6bf8072
--- /dev/null
+++ b/package_bgs/db/imbs.hpp
@@ -0,0 +1,178 @@
+/*
+*  IMBS Background Subtraction Library 
+*
+*  This file imbs.hpp contains the C++ OpenCV based implementation for
+*  IMBS algorithm described in
+*  D. D. Bloisi and L. Iocchi
+*  "Independent Multimodal Background Subtraction"
+*  In Proc. of the Third Int. Conf. on Computational Modeling of Objects
+*  Presented in Images: Fundamentals, Methods and Applications, pp. 39-44, 2012.
+*  Please, cite the above paper if you use IMBS.
+*  
+*  This software is provided without any warranty about its usability. 
+*  It is for educational purposes and should be regarded as such.
+*
+*  Written by Domenico D. Bloisi
+*
+*  Please, report suggestions/comments/bugs to
+*  domenico.bloisi@gmail.com
+*
+*/
+
+#ifndef __IMBS_HPP__
+#define __IMBS_HPP__
+
+//OPENCV
+#include <opencv2/core/core.hpp>
+#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+#include <opencv2/features2d/features2d.hpp>
+//C++
+#include <iostream>
+#include <vector>
+
+using namespace cv;
+using namespace std;
+
+class BackgroundSubtractorIMBS
+{
+public:
+  //! the default constructor
+  BackgroundSubtractorIMBS();
+  //! the full constructor
+  BackgroundSubtractorIMBS(double fps,
+    unsigned int fgThreshold=15,
+    unsigned int associationThreshold=5,
+    double samplingPeriod=500.,
+    unsigned int minBinHeight=2,
+    unsigned int numSamples=30,
+    double alpha=0.65,
+    double beta=1.15,
+    double tau_s=60.,
+    double tau_h=40.,
+    double minArea=30.,
+    double persistencePeriod=10000.,
+    bool morphologicalFiltering=false
+    );
+  //! the destructor
+  ~BackgroundSubtractorIMBS();
+  //! the update operator
+  void apply(InputArray image, OutputArray fgmask, double learningRate=-1.);
+
+  //! computes a background image which shows only the highest bin for each pixel
+  void getBackgroundImage(OutputArray backgroundImage) const;
+
+  //! re-initiaization method
+  void initialize(Size frameSize, int frameType);
+
+private:
+  //method for creating the background model
+  void createBg(unsigned int bg_sample_number);
+  //method for updating the background model
+  void updateBg();
+  //method for computing the foreground mask
+  void getFg();
+  //method for suppressing shadows and highlights
+  void hsvSuppression();    
+  //method for refining foreground mask
+  void filterFg();
+  //method for filtering out blobs smaller than a given area
+  void areaThresholding();
+  //method for getting the current time
+  double getTimestamp();
+  //method for converting from RGB to HSV
+  Mat convertImageRGBtoHSV(const Mat& imageRGB);
+  //method for changing the bg in case of sudden changes 
+  void changeBg();
+
+  //current input RGB frame
+  Mat frame;
+  vector<Mat> frameBGR;
+  //frame size
+  Size frameSize;
+  //frame type
+  int frameType;
+  //total number of pixels in frame
+  unsigned int numPixels;
+  //current background sample
+  Mat bgSample;
+  vector<Mat> bgSampleBGR;
+  //current background image which shows only the highest bin for each pixel
+  //(just for displaying purposes)
+  Mat bgImage;
+  //current foreground mask
+  Mat fgmask;
+
+  Mat fgfiltered;
+
+  //number of fps
+  double fps;
+  //time stamp in milliseconds (ms)
+  double timestamp;
+  //previous time stamp in milliseconds (ms)
+  double prev_timestamp;
+  double initial_tick_count;
+  //initial message to be shown until the first bg model is ready 
+  Mat initialMsgGray;
+  Mat initialMsgRGB;
+
+  //struct for modeling the background values for a single pixel
+  typedef struct {
+    Vec3b* binValues;
+    uchar* binHeights;
+    bool* isFg;
+  } Bins;
+
+  Bins* bgBins;
+public:
+  //struct for modeling the background values for the entire frame
+  typedef struct {
+    Vec3b* values;
+    bool* isValid;
+    bool* isFg;
+    uchar* counter;
+  } BgModel;
+private:
+  BgModel* bgModel;
+
+  //SHADOW SUPPRESSION PARAMETERS
+  float alpha;
+  float beta;
+  uchar tau_s;
+  uchar tau_h;
+
+  unsigned int minBinHeight;
+  unsigned int numSamples;
+  unsigned int samplingPeriod;
+  unsigned long prev_bg_frame_time;
+  unsigned int bg_frame_counter;
+  unsigned int associationThreshold;
+  unsigned int maxBgBins;
+  unsigned int nframes;
+
+  double minArea;
+  bool bg_reset;
+  unsigned int persistencePeriod;
+  bool prev_area;
+  bool sudden_change;
+  unsigned int fgThreshold;
+  uchar SHADOW_LABEL;
+  uchar PERSISTENCE_LABEL;
+  uchar FOREGROUND_LABEL;
+  //persistence map
+  unsigned int* persistenceMap;
+  Mat persistenceImage;
+
+  bool morphologicalFiltering;
+
+public:
+  unsigned int getMaxBgBins() {
+    return maxBgBins;
+  }
+  unsigned int getFgThreshold() {
+    return fgThreshold;
+  }
+  void getBgModel(BgModel bgModel_copy[], int size);
+};
+
+#endif //__IMBS_HPP__
diff --git a/package_bgs/dp/AdaptiveMedianBGS.cpp b/package_bgs/dp/AdaptiveMedianBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..16b3988c17c67cc60531f2cb9ea135d1336c6adc
--- /dev/null
+++ b/package_bgs/dp/AdaptiveMedianBGS.cpp
@@ -0,0 +1,140 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* AdaptiveMedianBGS.cpp
+*
+* Purpose: Implementation of the simple adaptive median background 
+*		  		 subtraction algorithm described in:
+*	  			 "Segmentation and tracking of piglets in images"
+* 						by McFarlane and Schofield
+*
+* Author: Donovan Parks, September 2007
+*
+******************************************************************************/
+
+#include <iostream>
+#include <stdlib.h>
+#include <cmath>
+
+#include "AdaptiveMedianBGS.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+void AdaptiveMedianBGS::Initalize(const BgsParams& param)
+{
+	m_params = (AdaptiveMedianParams&)param;
+
+	m_median = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+	cvSet(m_median.Ptr(), CV_RGB(BACKGROUND,BACKGROUND,BACKGROUND));
+}
+
+RgbImage* AdaptiveMedianBGS::Background()
+{
+	return &m_median;
+}
+
+void AdaptiveMedianBGS::InitModel(const RgbImage& data)
+{
+	// initialize the background model
+	for (unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			m_median(r,c) = data(r,c);
+		}
+	}
+}
+
+void AdaptiveMedianBGS::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	if(frame_num % m_params.SamplingRate() == 1)
+	{
+		// update background model
+		for (unsigned int r = 0; r < m_params.Height(); ++r)
+		{
+			for(unsigned int c = 0; c < m_params.Width(); ++c)
+			{
+				// perform conditional updating only if we are passed the learning phase
+				if(update_mask(r,c) == BACKGROUND || frame_num < m_params.LearningFrames())
+				{
+					for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+					{
+						if(data(r,c,ch) > m_median(r,c,ch))
+						{
+							m_median(r,c,ch)++;
+						}
+						else if(data(r,c,ch) < m_median(r,c,ch))
+						{
+							m_median(r,c,ch)--;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+void AdaptiveMedianBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, 
+																			unsigned char& low_threshold, unsigned char& high_threshold)
+{
+	// perform background subtraction
+	low_threshold = high_threshold = FOREGROUND;
+	
+	int diffR = abs(pixel(0) - m_median(r,c,0));
+	int diffG = abs(pixel(1) - m_median(r,c,1));
+	int diffB = abs(pixel(2) - m_median(r,c,2));
+	
+	if(diffR <= m_params.LowThreshold() && diffG <= m_params.LowThreshold() &&  diffB <= m_params.LowThreshold())
+	{
+		low_threshold = BACKGROUND;
+	}
+
+	if(diffR <= m_params.HighThreshold() && diffG <= m_params.HighThreshold() &&  diffB <= m_params.HighThreshold())
+	{
+		high_threshold = BACKGROUND;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the image data
+//Output:
+//  output - a pointer to the data of a gray value image
+//					(the memory should already be reserved) 
+//					values: 255-foreground, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void AdaptiveMedianBGS::Subtract(int frame_num, const RgbImage& data, 
+																	BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+	unsigned char low_threshold, high_threshold;
+
+	// update each pixel of the image
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{	
+			// perform background subtraction
+			SubtractPixel(r, c, data(r,c), low_threshold, high_threshold);
+
+			// setup silhouette mask
+			low_threshold_mask(r,c) = low_threshold;
+			high_threshold_mask(r,c) = high_threshold;
+		}
+	}
+}
+
diff --git a/package_bgs/dp/AdaptiveMedianBGS.h b/package_bgs/dp/AdaptiveMedianBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ea25af0ff3bf2c8b2956294015617347b17c672
--- /dev/null
+++ b/package_bgs/dp/AdaptiveMedianBGS.h
@@ -0,0 +1,89 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* AdaptiveMedianBGS.hpp
+*
+* Purpose: Implementation of the simple adaptive median background 
+*		  		 subtraction algorithm described in:
+*	  			 "Segmentation and tracking of piglets in images"
+* 						by McFarlane and Schofield
+*
+* Author: Donovan Parks, September 2007
+
+Example:
+		Algorithms::BackgroundSubtraction::AdaptiveMedianParams params;
+		params.SetFrameSize(width, height);
+		params.LowThreshold() = 40;
+		params.HighThreshold() = 2*params.LowThreshold();
+		params.SamplingRate() = 7;
+		params.LearningFrames() = 30;
+
+		Algorithms::BackgroundSubtraction::AdaptiveMedianBGS bgs;
+		bgs.Initalize(params);
+******************************************************************************/
+
+#include "Bgs.h"
+
+namespace Algorithms
+{
+	namespace BackgroundSubtraction
+	{
+		// --- Parameters used by the Adaptive Median BGS algorithm ---
+		class AdaptiveMedianParams : public BgsParams
+		{
+		public:
+			unsigned char &LowThreshold() { return m_low_threshold; }
+			unsigned char &HighThreshold() { return m_high_threshold; }
+
+			int &SamplingRate() { return m_samplingRate; }
+			int &LearningFrames() { return m_learning_frames; }
+
+		private:
+			unsigned char m_low_threshold;
+			unsigned char m_high_threshold;
+
+			int m_samplingRate;
+			int m_learning_frames;
+		};
+
+
+		// --- Adaptive Median BGS algorithm ---
+		class AdaptiveMedianBGS : public Bgs 
+		{
+		public:
+			virtual ~AdaptiveMedianBGS() {}
+
+			void Initalize(const BgsParams& param);
+
+			void InitModel(const RgbImage& data);
+			void Subtract(int frame_num, const RgbImage& data,  
+											BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+			void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+			RgbImage* Background();
+
+		private:	
+			void SubtractPixel(int r, int c, const RgbPixel& pixel, 
+													unsigned char& low_threshold, unsigned char& high_threshold);
+
+			AdaptiveMedianParams m_params;
+
+			RgbImage m_median;
+		};
+	};
+};
diff --git a/package_bgs/dp/Bgs.h b/package_bgs/dp/Bgs.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1ae23c25b90d1b5795afaef2e3d96f641eaac60
--- /dev/null
+++ b/package_bgs/dp/Bgs.h
@@ -0,0 +1,67 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Bgs.hpp
+*
+* Purpose: Base class for BGS algorithms.
+*
+* Author: Donovan Parks, October 2007
+*
+******************************************************************************/
+
+#ifndef BGS_H_
+#define BGS_H_
+
+#include "Image.h"
+#include "BgsParams.h"
+
+namespace Algorithms
+{
+	namespace BackgroundSubtraction
+	{
+		class Bgs
+		{
+		public:
+			static const int BACKGROUND = 0;
+			static const int FOREGROUND = 255;
+
+			virtual ~Bgs() {}
+
+			// Initialize any data required by the BGS algorithm. Should be called once before calling
+			// any of the following functions.
+			virtual void Initalize(const BgsParams& param) = 0;
+
+			// Initialize the background model. Typically, the background model is initialized using the first
+			// frame of the incoming video stream, but alternatives are possible.
+			virtual void InitModel(const RgbImage& data) = 0;
+
+			// Subtract the current frame from the background model and produce a binary foreground mask using
+			// both a low and high threshold value.
+			virtual void Subtract(int frame_num, const RgbImage& data,  
+															BwImage& low_threshold_mask, BwImage& high_threshold_mask) = 0;	
+
+			// Update the background model. Only pixels set to background in update_mask are updated.
+			virtual void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask) = 0;
+
+			// Return the current background model.
+			virtual RgbImage *Background() = 0;
+		};
+	};
+};
+
+#endif
\ No newline at end of file
diff --git a/package_bgs/dp/BgsParams.h b/package_bgs/dp/BgsParams.h
new file mode 100644
index 0000000000000000000000000000000000000000..c3bad830f254eb6c6ba45750610abab8283fed2c
--- /dev/null
+++ b/package_bgs/dp/BgsParams.h
@@ -0,0 +1,59 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* BgsParams.hpp
+*
+* Purpose: Base class for BGS parameters. Any parameters common to all BGS
+*					 algorithms should be specified directly in this class.
+*
+* Author: Donovan Parks, May 2008
+*
+******************************************************************************/
+
+#ifndef BGS_PARAMS_H_
+#define BGS_PARAMS_H_
+
+namespace Algorithms
+{
+	namespace BackgroundSubtraction
+	{
+		class BgsParams
+		{
+		public:
+			virtual ~BgsParams() {}
+
+			virtual void SetFrameSize(unsigned int width, unsigned int height)
+			{
+				m_width = width;
+				m_height = height;
+				m_size = width*height;
+			}
+
+			unsigned int &Width() { return m_width; }
+			unsigned int &Height() { return m_height; }
+			unsigned int &Size() { return m_size; }
+
+		protected:
+			unsigned int m_width;
+			unsigned int m_height;
+			unsigned int m_size;
+		};
+	};
+};
+
+#endif
\ No newline at end of file
diff --git a/package_bgs/dp/DPAdaptiveMedianBGS.cpp b/package_bgs/dp/DPAdaptiveMedianBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d7ebcd19ab53def6396097f32ba5865ddd2f520b
--- /dev/null
+++ b/package_bgs/dp/DPAdaptiveMedianBGS.cpp
@@ -0,0 +1,104 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPAdaptiveMedianBGS.h"
+
+DPAdaptiveMedianBGS::DPAdaptiveMedianBGS() : firstTime(true), frameNumber(0), showOutput(true), threshold(40), samplingRate(7), learningFrames(30)
+{
+  std::cout << "DPAdaptiveMedianBGS()" << std::endl;
+}
+
+DPAdaptiveMedianBGS::~DPAdaptiveMedianBGS()
+{
+  std::cout << "~DPAdaptiveMedianBGS()" << std::endl;
+}
+
+void DPAdaptiveMedianBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold;
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    params.SamplingRate() = samplingRate;
+    params.LearningFrames() = learningFrames;
+    
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("Adaptive Median (McFarlane&Schofield)", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPAdaptiveMedianBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPAdaptiveMedianBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "samplingRate", samplingRate);
+  cvWriteInt(fs, "learningFrames", learningFrames);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPAdaptiveMedianBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPAdaptiveMedianBGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadIntByName(fs, 0, "threshold", 40);
+  samplingRate = cvReadIntByName(fs, 0, "samplingRate", 7);
+  learningFrames = cvReadIntByName(fs, 0, "learningFrames", 30);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/dp/DPAdaptiveMedianBGS.h b/package_bgs/dp/DPAdaptiveMedianBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..05ac9c3364be2b0a9689af12b1116c4e4c9d3ede
--- /dev/null
+++ b/package_bgs/dp/DPAdaptiveMedianBGS.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "AdaptiveMedianBGS.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPAdaptiveMedianBGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  AdaptiveMedianParams params;
+  AdaptiveMedianBGS bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  int threshold;
+  int samplingRate;
+  int learningFrames;
+  bool showOutput;
+
+public:
+  DPAdaptiveMedianBGS();
+  ~DPAdaptiveMedianBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/DPEigenbackgroundBGS.cpp b/package_bgs/dp/DPEigenbackgroundBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6d2c6ba12cdf426b49831559f72bf443a5f904c5
--- /dev/null
+++ b/package_bgs/dp/DPEigenbackgroundBGS.cpp
@@ -0,0 +1,106 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPEigenbackgroundBGS.h"
+
+DPEigenbackgroundBGS::DPEigenbackgroundBGS() : firstTime(true), frameNumber(0), showOutput(true), threshold(225), historySize(20), embeddedDim(10)
+{
+  std::cout << "DPEigenbackgroundBGS()" << std::endl;
+}
+
+DPEigenbackgroundBGS::~DPEigenbackgroundBGS()
+{
+  std::cout << "~DPEigenbackgroundBGS()" << std::endl;
+}
+
+void DPEigenbackgroundBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold; //15*15;
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    //params.HistorySize() = 100;
+    params.HistorySize() = historySize;
+    //params.EmbeddedDim() = 20;
+    params.EmbeddedDim() = embeddedDim;
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("Eigenbackground (Oliver)", foreground);
+
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPEigenbackgroundBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPEigenbackgroundBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "historySize", historySize);
+  cvWriteInt(fs, "embeddedDim", embeddedDim);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPEigenbackgroundBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPEigenbackgroundBGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadIntByName(fs, 0, "threshold", 225);
+  historySize = cvReadIntByName(fs, 0, "historySize", 20);
+  embeddedDim = cvReadIntByName(fs, 0, "embeddedDim", 10);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/dp/DPEigenbackgroundBGS.h b/package_bgs/dp/DPEigenbackgroundBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..df558fe45cdbea23199685eafc5e2d44a54fec01
--- /dev/null
+++ b/package_bgs/dp/DPEigenbackgroundBGS.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "Eigenbackground.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPEigenbackgroundBGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  EigenbackgroundParams params;
+  Eigenbackground bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  int threshold;
+  int historySize;
+  int embeddedDim;
+  bool showOutput;
+
+public:
+  DPEigenbackgroundBGS();
+  ~DPEigenbackgroundBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/DPGrimsonGMMBGS.cpp b/package_bgs/dp/DPGrimsonGMMBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d6ad42fa6c59c4a356dccdf0ce054e8ceeaed42
--- /dev/null
+++ b/package_bgs/dp/DPGrimsonGMMBGS.cpp
@@ -0,0 +1,105 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPGrimsonGMMBGS.h"
+
+DPGrimsonGMMBGS::DPGrimsonGMMBGS() : firstTime(true), frameNumber(0), showOutput(true), threshold(9.0), alpha(0.01), gaussians(3)
+{
+  std::cout << "DPGrimsonGMMBGS()" << std::endl;
+}
+
+DPGrimsonGMMBGS::~DPGrimsonGMMBGS()
+{
+  std::cout << "~DPGrimsonGMMBGS()" << std::endl;
+}
+
+void DPGrimsonGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold; //3.0f*3.0f;
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    //params.Alpha() = 0.001f;
+    params.Alpha() = alpha; //0.01f;
+    params.MaxModes() = gaussians; //3;
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("GMM (Grimson)", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPGrimsonGMMBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPGrimsonGMMBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "gaussians", gaussians);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPGrimsonGMMBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPGrimsonGMMBGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 9.0);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.01);
+  gaussians = cvReadIntByName(fs, 0, "gaussians", 3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/dp/DPGrimsonGMMBGS.h b/package_bgs/dp/DPGrimsonGMMBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..37e2a33ab31e791ddb6371ad37e4f77d64ce71ed
--- /dev/null
+++ b/package_bgs/dp/DPGrimsonGMMBGS.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "GrimsonGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPGrimsonGMMBGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  GrimsonParams params;
+  GrimsonGMM bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  int gaussians;
+  bool showOutput;
+
+public:
+  DPGrimsonGMMBGS();
+  ~DPGrimsonGMMBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/DPMeanBGS.cpp b/package_bgs/dp/DPMeanBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..13260b469c9d8eb50d05d9218513b46983162a37
--- /dev/null
+++ b/package_bgs/dp/DPMeanBGS.cpp
@@ -0,0 +1,105 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPMeanBGS.h"
+
+DPMeanBGS::DPMeanBGS() : firstTime(true), frameNumber(0), threshold(2700), alpha(1e-6f), learningFrames(30), showOutput(true)
+{
+  std::cout << "DPMeanBGS()" << std::endl;
+}
+
+DPMeanBGS::~DPMeanBGS()
+{
+  std::cout << "~DPMeanBGS()" << std::endl;
+}
+
+void DPMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold; //3*30*30; // 2700
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    //params.Alpha() = 1e-6f;
+    params.Alpha() = alpha;
+    params.LearningFrames() = learningFrames;//30;
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("Temporal Mean (Donovan Parks)", foreground);
+
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPMeanBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPMeanBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "learningFrames", learningFrames);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPMeanBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPMeanBGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadIntByName(fs, 0, "threshold", 2700);
+  alpha = cvReadRealByName(fs, 0, "alpha", 1e-6f);
+  learningFrames = cvReadIntByName(fs, 0, "learningFrames", 30);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/dp/DPMeanBGS.h b/package_bgs/dp/DPMeanBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..b119ac4d6667478d37ceab0e234032f915834649
--- /dev/null
+++ b/package_bgs/dp/DPMeanBGS.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "MeanBGS.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPMeanBGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  MeanParams params;
+  MeanBGS bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  int threshold;
+  double alpha;
+  int learningFrames;
+  bool showOutput;
+
+public:
+  DPMeanBGS();
+  ~DPMeanBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/DPPratiMediodBGS.cpp b/package_bgs/dp/DPPratiMediodBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..65c3ef3bc6e5115422bced7ab003face6381302a
--- /dev/null
+++ b/package_bgs/dp/DPPratiMediodBGS.cpp
@@ -0,0 +1,107 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPPratiMediodBGS.h"
+
+DPPratiMediodBGS::DPPratiMediodBGS() : firstTime(true), frameNumber(0), threshold(30), samplingRate(5), historySize(16), weight(5), showOutput(true)
+{
+  std::cout << "DPPratiMediodBGS()" << std::endl;
+}
+
+DPPratiMediodBGS::~DPPratiMediodBGS()
+{
+  std::cout << "~DPPratiMediodBGS()" << std::endl;
+}
+
+void DPPratiMediodBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold;
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    params.SamplingRate() = samplingRate;
+    params.HistorySize() = historySize;
+    params.Weight() = weight;
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("Temporal Median (Cucchiara&Calderara)", foreground);
+
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPPratiMediodBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPPratiMediodBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "threshold", threshold);
+  cvWriteInt(fs, "samplingRate", samplingRate);
+  cvWriteInt(fs, "historySize", historySize);
+  cvWriteInt(fs, "weight", weight);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPPratiMediodBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPPratiMediodBGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadIntByName(fs, 0, "threshold", 30);
+  samplingRate = cvReadIntByName(fs, 0, "samplingRate", 5);
+  historySize = cvReadIntByName(fs, 0, "historySize", 16);
+  weight = cvReadIntByName(fs, 0, "weight", 5);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/dp/DPPratiMediodBGS.h b/package_bgs/dp/DPPratiMediodBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..657dc1b3e51b95cf4033329344ce3aba037fa57f
--- /dev/null
+++ b/package_bgs/dp/DPPratiMediodBGS.h
@@ -0,0 +1,57 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "PratiMediodBGS.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPPratiMediodBGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  PratiParams params;
+  PratiMediodBGS bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  int threshold;
+  int samplingRate;
+  int historySize;
+  int weight;
+  bool showOutput;
+
+public:
+  DPPratiMediodBGS();
+  ~DPPratiMediodBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/DPTextureBGS.cpp b/package_bgs/dp/DPTextureBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2d34342e1151fb8c174a9291781622a63fc10a0a
--- /dev/null
+++ b/package_bgs/dp/DPTextureBGS.cpp
@@ -0,0 +1,156 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPTextureBGS.h"
+
+DPTextureBGS::DPTextureBGS() : firstTime(true), showOutput(true)
+  //, enableFiltering(true)
+{
+  std::cout << "DPTextureBGS()" << std::endl;
+}
+
+DPTextureBGS::~DPTextureBGS()
+{
+  delete[] bgModel; // ~10Kb (25.708-15.968)
+  delete[] modeArray;
+  delete[] curTextureHist; // ~10Kb (16-6.396)
+  //cvReleaseStructuringElement(&dilateElement);
+  //cvReleaseStructuringElement(&erodeElement);
+  image.ReleaseImage();
+  fgMask.ReleaseImage();
+  tempMask.ReleaseImage();
+  texture.ReleaseImage();
+  std::cout << "~DPTextureBGS()" << std::endl;
+}
+
+void DPTextureBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+  {
+    width	= img_input.size().width;
+    height = img_input.size().height;
+    size = width * height;
+
+    // input image
+    image = cvCreateImage(cvSize(width, height), 8, 3);
+    cvCopy(frame, image.Ptr());	
+
+    // foreground masks
+    fgMask = cvCreateImage(cvSize(width, height), 8, 1);
+    tempMask = cvCreateImage(cvSize(width, height), 8, 1);
+    cvZero(fgMask.Ptr());
+    cvZero(tempMask.Ptr());
+    
+    // create background model
+    bgModel = new TextureArray[size];
+    texture = cvCreateImage(cvSize(width, height), 8, 3);
+    cvZero(texture.Ptr());
+    modeArray = new unsigned char[size];
+    curTextureHist = new TextureHistogram[size];
+
+    // initialize background model
+    bgs.LBP(image, texture);
+    bgs.Histogram(texture, curTextureHist);
+    for(int y = REGION_R+TEXTURE_R; y < height-REGION_R-TEXTURE_R; ++y)
+    {
+      for(int x = REGION_R+TEXTURE_R; x < width-REGION_R-TEXTURE_R; ++x)
+      {
+        int index = x+y*width;
+      
+        for(int m = 0; m < NUM_MODES; ++m)
+        {
+          for(int i = 0; i < NUM_BINS; ++i)
+          {			
+            bgModel[index].mode[m].r[i] = curTextureHist[index].r[i];
+            bgModel[index].mode[m].g[i] = curTextureHist[index].g[i];
+            bgModel[index].mode[m].b[i] = curTextureHist[index].b[i];
+          }
+        }
+      }
+    }
+
+    //dilateElement = cvCreateStructuringElementEx(7, 7, 3, 3,	CV_SHAPE_RECT);
+    //erodeElement = cvCreateStructuringElementEx(3, 3, 1, 1,	CV_SHAPE_RECT);
+
+    saveConfig();
+    firstTime = false;
+  }
+  
+  cvCopy(frame, image.Ptr());	
+
+  // perform background subtraction
+  bgs.LBP(image, texture);
+  bgs.Histogram(texture, curTextureHist);
+  bgs.BgsCompare(bgModel, curTextureHist, modeArray, THRESHOLD, fgMask);
+  
+  //if(enableFiltering)
+  //{
+  //  // size filtering
+  //  ConnectedComponents cc;
+  //  CBlobResult largeBlobs;
+  //  cc.SetImage(&fgMask);
+  //  cc.Find(127);
+  //  cc.FilterMinArea(size/30, largeBlobs);
+  //  fgMask.Clear();
+  //  cc.ColorBlobs(fgMask.Ptr(), largeBlobs, CV_RGB(255,255,255));
+  //  largeBlobs.ClearBlobs();
+
+  //  // morphological operators
+  //  cvDilate(fgMask.Ptr(), fgMask.Ptr(), dilateElement, 1);
+  //  cvErode(fgMask.Ptr(), fgMask.Ptr(), erodeElement, 1);
+  //}
+
+  cv::Mat foreground(fgMask.Ptr());
+  if(!foreground.empty())
+    foreground.copyTo(img_output);
+  
+  if(showOutput)
+    cv::imshow("Texture BGS (Donovan Parks)", foreground);
+
+  // update background subtraction		
+  bgs.UpdateModel(fgMask, bgModel, curTextureHist, modeArray);
+  
+  delete frame;
+}
+
+void DPTextureBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPTextureBGS.xml", 0, CV_STORAGE_WRITE);
+
+  //cvWriteReal(fs, "alpha", alpha);
+  //cvWriteInt(fs, "enableFiltering", enableFiltering);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPTextureBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPTextureBGS.xml", 0, CV_STORAGE_READ);
+  
+  //alpha = cvReadRealByName(fs, 0, "alpha", 1e-6f);
+  //enableFiltering = cvReadIntByName(fs, 0, "enableFiltering", true);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/dp/DPTextureBGS.h b/package_bgs/dp/DPTextureBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..daa6a554481811cf3fa1218f16e5612359cc1579
--- /dev/null
+++ b/package_bgs/dp/DPTextureBGS.h
@@ -0,0 +1,60 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "TextureBGS.h"
+//#include "ConnectedComponents.h"
+
+class DPTextureBGS : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+
+  int width;
+  int height;
+  int size;
+  TextureBGS bgs;
+  IplImage* frame;
+  RgbImage image;
+  BwImage fgMask;
+  BwImage tempMask;
+  TextureArray* bgModel;
+  RgbImage texture;
+  unsigned char* modeArray;
+  TextureHistogram* curTextureHist;
+  //ConnectedComponents cc;
+  //CBlobResult largeBlobs;
+  //IplConvKernel* dilateElement;
+  //IplConvKernel* erodeElement;
+  //bool enableFiltering;
+
+public:
+  DPTextureBGS();
+  ~DPTextureBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/package_bgs/dp/DPWrenGABGS.cpp b/package_bgs/dp/DPWrenGABGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d7241b1db6ce9ef0c219b5fbaa28e7cb2abc2963
--- /dev/null
+++ b/package_bgs/dp/DPWrenGABGS.cpp
@@ -0,0 +1,105 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPWrenGABGS.h"
+
+DPWrenGABGS::DPWrenGABGS() : firstTime(true), frameNumber(0), threshold(12.25f), alpha(0.005f), learningFrames(30), showOutput(true)
+{
+  std::cout << "DPWrenGABGS()" << std::endl;
+}
+
+DPWrenGABGS::~DPWrenGABGS()
+{
+  std::cout << "~DPWrenGABGS()" << std::endl;
+}
+
+void DPWrenGABGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold; //3.5f*3.5f;
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    params.Alpha() = alpha; //0.005f;
+    params.LearningFrames() = learningFrames; //30;
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("Gaussian Average (Wren)", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPWrenGABGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPWrenGABGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "learningFrames", learningFrames);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPWrenGABGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPWrenGABGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 12.25f);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.005f);
+  learningFrames = cvReadIntByName(fs, 0, "learningFrames", 30);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
+
diff --git a/package_bgs/dp/DPWrenGABGS.h b/package_bgs/dp/DPWrenGABGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e545c5fe0038a560b452f9dc778267239aa2f66
--- /dev/null
+++ b/package_bgs/dp/DPWrenGABGS.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "WrenGA.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPWrenGABGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  WrenParams params;
+  WrenGA bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  int learningFrames;
+  bool showOutput;
+
+public:
+  DPWrenGABGS();
+  ~DPWrenGABGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/DPZivkovicAGMMBGS.cpp b/package_bgs/dp/DPZivkovicAGMMBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..16f991cc96ed1d43683b455764464ff1c4dd1ab8
--- /dev/null
+++ b/package_bgs/dp/DPZivkovicAGMMBGS.cpp
@@ -0,0 +1,104 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "DPZivkovicAGMMBGS.h"
+
+DPZivkovicAGMMBGS::DPZivkovicAGMMBGS() : firstTime(true), frameNumber(0), showOutput(true), threshold(25.0f), alpha(0.001f), gaussians(3)
+{
+  std::cout << "DPZivkovicAGMMBGS()" << std::endl;
+}
+
+DPZivkovicAGMMBGS::~DPZivkovicAGMMBGS()
+{
+  std::cout << "~DPZivkovicAGMMBGS()" << std::endl;
+}
+
+void DPZivkovicAGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold; //5.0f*5.0f;
+    params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+    params.Alpha() = alpha; //0.001f;
+    params.MaxModes() = gaussians; //3;
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("Gaussian Mixture Model (Zivkovic)", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void DPZivkovicAGMMBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPZivkovicAGMMBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteInt(fs, "gaussians", gaussians);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void DPZivkovicAGMMBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/DPZivkovicAGMMBGS.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 25.0f);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.001f);
+  gaussians = cvReadIntByName(fs, 0, "gaussians", 3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/dp/DPZivkovicAGMMBGS.h b/package_bgs/dp/DPZivkovicAGMMBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..d213341e745ee0e6fd771660933a73a56da8f46e
--- /dev/null
+++ b/package_bgs/dp/DPZivkovicAGMMBGS.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "ZivkovicAGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class DPZivkovicAGMMBGS : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  ZivkovicParams params;
+  ZivkovicAGMM bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  int gaussians;
+  bool showOutput;
+
+public:
+  DPZivkovicAGMMBGS();
+  ~DPZivkovicAGMMBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/dp/Eigenbackground.cpp b/package_bgs/dp/Eigenbackground.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2d2c3ef3d85a26d0653e7b17f3486a4e4affa903
--- /dev/null
+++ b/package_bgs/dp/Eigenbackground.cpp
@@ -0,0 +1,190 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Eigenbackground.cpp
+*
+* Purpose: Implementation of the Eigenbackground background subtraction 
+*					 algorithm developed by Oliver et al.
+*
+* Author: Donovan Parks, September 2007
+*
+* "A Bayesian Computer Vision System for Modeling Human Interactions"
+*   Nuria Oliver, Barbara Rosario, Alex P. Pentland 2000
+*
+******************************************************************************/
+
+#include "Eigenbackground.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+Eigenbackground::Eigenbackground()
+{
+	m_pcaData = NULL;
+	m_pcaAvg = NULL;
+	m_eigenValues = NULL;
+	m_eigenVectors = NULL;
+}
+
+Eigenbackground::~Eigenbackground()
+{
+	if(m_pcaData != NULL) cvReleaseMat(&m_pcaData);
+	if(m_pcaAvg != NULL) cvReleaseMat(&m_pcaAvg);
+	if(m_eigenValues != NULL) cvReleaseMat(&m_eigenValues);
+	if(m_eigenVectors != NULL) cvReleaseMat(&m_eigenVectors);
+}
+
+void Eigenbackground::Initalize(const BgsParams& param)
+{
+	m_params = (EigenbackgroundParams&)param;
+	
+	m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+	m_background.Clear();
+}
+
+void Eigenbackground::InitModel(const RgbImage& data)
+{
+	if(m_pcaData != NULL) cvReleaseMat(&m_pcaData);
+	if(m_pcaAvg != NULL) cvReleaseMat(&m_pcaAvg);
+	if(m_eigenValues != NULL) cvReleaseMat(&m_eigenValues);
+	if(m_eigenVectors != NULL) cvReleaseMat(&m_eigenVectors);
+
+	m_pcaData = cvCreateMat(m_params.HistorySize(), m_params.Size()*3, CV_8UC1);
+
+	m_background.Clear();
+}
+
+void Eigenbackground::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	// the eigenbackground model is not updated (serious limitation!)
+}
+
+void Eigenbackground::Subtract(int frame_num, const RgbImage& data,  
+																BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+	// create eigenbackground
+	if(frame_num == m_params.HistorySize())
+	{
+		// create the eigenspace
+		m_pcaAvg = cvCreateMat( 1, m_pcaData->cols, CV_32F );
+		m_eigenValues = cvCreateMat( m_pcaData->rows, 1, CV_32F ); 
+		m_eigenVectors = cvCreateMat( m_pcaData->rows, m_pcaData->cols, CV_32F );
+		cvCalcPCA(m_pcaData, m_pcaAvg, m_eigenValues, m_eigenVectors, CV_PCA_DATA_AS_ROW);
+
+		int index = 0;
+		for(unsigned int r = 0; r < m_params.Height(); ++r)
+		{
+			for(unsigned int c = 0; c < m_params.Width(); ++c)
+			{
+				for(int ch = 0; ch < m_background.Ptr()->nChannels; ++ch)
+				{
+					m_background(r,c,0) = static_cast<unsigned char>(cvmGet(m_pcaAvg,0,index)+0.5);
+					index++;
+				}
+			}
+		}
+	}
+
+	if(frame_num >= m_params.HistorySize())
+	{
+		// project new image into the eigenspace
+		int w = data.Ptr()->width;
+		int h = data.Ptr()->height;
+		int ch = data.Ptr()->nChannels;
+		CvMat* dataPt = cvCreateMat(1, w*h*ch, CV_8UC1); 
+		CvMat data_row;
+		cvGetRow(dataPt, &data_row, 0);
+		cvReshape(&data_row, &data_row, 3, data.Ptr()->height); 
+		cvCopy(data.Ptr(), &data_row); 
+
+		CvMat* proj = cvCreateMat(1, m_params.EmbeddedDim(), CV_32F);
+		cvProjectPCA(dataPt, m_pcaAvg, m_eigenVectors, proj);
+
+		// reconstruct point
+		CvMat* result = cvCreateMat(1, m_pcaData->cols, CV_32F);
+		cvBackProjectPCA(proj, m_pcaAvg, m_eigenVectors, result);
+
+		// calculate Euclidean distance between new image and its eigenspace projection
+		int index = 0;
+		for(unsigned int r = 0; r < m_params.Height(); ++r)
+		{
+			for(unsigned int c = 0; c < m_params.Width(); ++c)
+			{
+				double dist = 0;
+				bool bgLow = true;
+				bool bgHigh = true;
+				for(int ch = 0; ch < 3; ++ch)
+				{
+					dist = (data(r,c,ch) - cvmGet(result,0,index))*(data(r,c,ch) - cvmGet(result,0,index));
+					if(dist > m_params.LowThreshold())
+						bgLow = false;
+					if(dist > m_params.HighThreshold())
+						bgHigh = false;
+					index++;
+				}
+				
+				if(!bgLow)
+				{
+					low_threshold_mask(r,c) = FOREGROUND;
+				}
+				else
+				{
+					low_threshold_mask(r,c) = BACKGROUND;
+				}
+
+				if(!bgHigh)
+				{
+					high_threshold_mask(r,c) = FOREGROUND;
+				}
+				else
+				{
+					high_threshold_mask(r,c) = BACKGROUND;
+				}
+			}
+		}
+		
+		cvReleaseMat(&result);
+		cvReleaseMat(&proj);		
+		cvReleaseMat(&dataPt);
+	}
+	else 
+	{
+		// set entire image to background since there is not enough information yet
+		// to start performing background subtraction
+		for(unsigned int r = 0; r < m_params.Height(); ++r)
+		{
+			for(unsigned int c = 0; c < m_params.Width(); ++c)
+			{
+				low_threshold_mask(r,c) = BACKGROUND;
+				high_threshold_mask(r,c) = BACKGROUND;
+			}
+		}
+	}
+
+	UpdateHistory(frame_num, data);
+}
+
+void Eigenbackground::UpdateHistory(int frame_num, const RgbImage& new_frame)
+{
+	if(frame_num < m_params.HistorySize())
+	{
+		CvMat src_row;
+		cvGetRow(m_pcaData, &src_row, frame_num);
+		cvReshape(&src_row, &src_row, 3, new_frame.Ptr()->height);
+		cvCopy(new_frame.Ptr(), &src_row);
+	}
+}
diff --git a/package_bgs/dp/Eigenbackground.h b/package_bgs/dp/Eigenbackground.h
new file mode 100644
index 0000000000000000000000000000000000000000..b86ac92a66bfeb6b07c694f1599b61f2bdb9b5cf
--- /dev/null
+++ b/package_bgs/dp/Eigenbackground.h
@@ -0,0 +1,101 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Eigenbackground.hpp
+*
+* Purpose: Implementation of the Eigenbackground background subtraction 
+*					 algorithm developed by Oliver et al.
+*
+* Author: Donovan Parks, September 2007
+*
+* "A Bayesian Computer Vision System for Modeling Human Interactions"
+*   Nuria Oliver, Barbara Rosario, Alex P. Pentland 2000
+
+Example:
+Algorithms::BackgroundSubtraction::EigenbackgroundParams params;
+params.SetFrameSize(width, height);
+params.LowThreshold() = 15*15;
+params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+params.HistorySize() = 100;
+params.EmbeddedDim() = 20;
+
+Algorithms::BackgroundSubtraction::Eigenbackground bgs;
+bgs.Initalize(params);
+******************************************************************************/
+
+#ifndef _ELGAMMAL_H_
+#define _ELGAMMAL_H_
+
+#include "Bgs.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    // --- Parameters used by the Mean BGS algorithm ---
+    class EigenbackgroundParams : public BgsParams
+    {
+    public:
+      float &LowThreshold() { return m_low_threshold; }
+      float &HighThreshold() { return m_high_threshold; }
+
+      int &HistorySize() { return m_history_size; }
+      int &EmbeddedDim() { return m_dim; }
+
+    private:
+      // A pixel will be classified as foreground if the squared distance of any
+      // color channel is greater than the specified threshold
+      float m_low_threshold;
+      float m_high_threshold;
+
+      int m_history_size;			// number frames used to create eigenspace
+      int m_dim;							// eigenspace dimensionality
+    };
+
+    // --- Eigenbackground BGS algorithm ---
+    class Eigenbackground : public Bgs
+    {
+    public:
+      Eigenbackground();
+      ~Eigenbackground();
+
+      void Initalize(const BgsParams& param);
+
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data,  
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+      RgbImage* Background() { return &m_background; }
+
+    private:
+      void UpdateHistory(int frameNum, const RgbImage& newFrame);
+
+      EigenbackgroundParams m_params;
+
+      CvMat* m_pcaData;
+      CvMat* m_pcaAvg;
+      CvMat* m_eigenValues; 
+      CvMat* m_eigenVectors;
+
+      RgbImage m_background;
+    };
+  };
+};
+
+#endif
\ No newline at end of file
diff --git a/package_bgs/dp/Error.cpp b/package_bgs/dp/Error.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1bd87db824e308d63181f5ea6cc32a6304d6129f
--- /dev/null
+++ b/package_bgs/dp/Error.cpp
@@ -0,0 +1,57 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Error.cpp
+*
+* Purpose:  Error checking routines.
+*
+* Author: Donovan Parks, July 2007
+*
+******************************************************************************/
+
+#include <iostream> 
+#include <fstream>
+
+#include "Error.h"
+
+using namespace std;
+
+ofstream traceFile;
+
+bool Error(const char* msg, const char* code, int data)
+{
+  cerr << code << ": " << msg << endl;
+
+  return false;
+}
+
+bool TraceInit(const char* filename)
+{
+  traceFile.open(filename);
+  return traceFile.is_open();
+}
+
+void Trace(const char* msg)
+{
+  traceFile << msg << endl;
+}
+
+void TraceClose()
+{
+  traceFile.close();
+}
diff --git a/package_bgs/dp/Error.h b/package_bgs/dp/Error.h
new file mode 100644
index 0000000000000000000000000000000000000000..cdbb222c4bdc9ec92b5c2aad3bd02c06fd39c2b9
--- /dev/null
+++ b/package_bgs/dp/Error.h
@@ -0,0 +1,36 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Error.h
+*
+* Purpose:  Error checking routines.
+*
+* Author: Donovan Parks, July 2007
+*
+******************************************************************************/
+
+#ifndef ERROR_H
+#define ERROR_H
+
+bool Error(const char* msg, const char* code, int data);
+
+bool TraceInit(const char* filename);
+void Trace(const char* msg);
+void TraceClose();
+
+#endif
diff --git a/package_bgs/dp/GrimsonGMM.cpp b/package_bgs/dp/GrimsonGMM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5788dc9d1c77d992ac145167f51c8da1694703fe
--- /dev/null
+++ b/package_bgs/dp/GrimsonGMM.cpp
@@ -0,0 +1,332 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* GrimsonGMM.cpp
+*
+* Purpose: Implementation of the Gaussian mixture model (GMM) background 
+*		  		 subtraction described in:
+*	  			 "Adaptive background mixture models for real-time tracking"
+* 						by Chris Stauffer and W.E.L Grimson
+*
+* Author: Donovan Parks, September 2007
+*
+* This code is based on code by Z. Zivkovic's written for his enhanced GMM
+* background subtraction algorithm: 
+*
+*	"Improved adaptive Gausian mixture model for background subtraction"
+*		Z.Zivkovic 
+*		International Conference Pattern Recognition, UK, August, 2004
+*
+*
+* "Efficient Adaptive Density Estimapion per Image Pixel for the 
+*			Task of Background Subtraction"
+*		Z.Zivkovic, F. van der Heijden 
+*		Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+******************************************************************************/
+
+#include "GrimsonGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+int compareGMM(const void* _gmm1, const void* _gmm2)
+{
+	GMM gmm1 = *(GMM*)_gmm1;
+	GMM gmm2 = *(GMM*)_gmm2;
+
+	if(gmm1.significants < gmm2.significants)
+		return 1;
+	else if(gmm1.significants == gmm2.significants)
+		return 0;
+	else
+		return -1;
+}
+
+GrimsonGMM::GrimsonGMM()
+{
+	m_modes = NULL;
+}
+
+GrimsonGMM::~GrimsonGMM()
+{
+	if(m_modes != NULL) 
+		delete[] m_modes;
+}
+
+void GrimsonGMM::Initalize(const BgsParams& param)
+{
+	m_params = (GrimsonParams&)param;
+
+	// Tbf - the threshold
+	m_bg_threshold = 0.75f;	// 1-cf from the paper 
+
+	// Tgenerate - the threshold
+	m_variance = 36.0f;		// sigma for the new mode
+
+	// GMM for each pixel
+	m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
+
+	// used modes per pixel
+	m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
+
+	m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+}
+
+RgbImage* GrimsonGMM::Background()
+{
+	return &m_background;
+}
+
+void GrimsonGMM::InitModel(const RgbImage& data)
+{
+	m_modes_per_pixel.Clear();
+
+	for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+	{
+		m_modes[i].weight = 0;
+		m_modes[i].variance = 0;
+		m_modes[i].muR = 0;
+		m_modes[i].muG = 0;
+		m_modes[i].muB = 0;
+		m_modes[i].significants = 0;
+	}
+}
+
+void GrimsonGMM::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	// it doesn't make sense to have conditional updates in the GMM framework
+}
+
+void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, 
+																	unsigned char& low_threshold, unsigned char& high_threshold)
+{
+	// calculate distances to the modes (+ sort???)
+	// here we need to go in descending order!!!
+	long pos;
+	bool bFitsPDF=false;
+	bool bBackgroundLow=false;
+	bool bBackgroundHigh=false;
+
+	float fOneMinAlpha = 1-m_params.Alpha();
+
+	float totalWeight = 0.0f;
+
+	// calculate number of Gaussians to include in the background model
+	int backgroundGaussians = 0;
+	double sum = 0.0;
+	for(int i = 0; i < numModes; ++i)
+	{
+		if(sum < m_bg_threshold)
+		{
+			backgroundGaussians++;
+			sum += m_modes[posPixel+i].weight;
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	// update all distributions and check for match with current pixel
+	for (int iModes=0; iModes < numModes; iModes++)
+	{
+		pos=posPixel+iModes;
+		float weight = m_modes[pos].weight;
+
+		// fit not found yet
+		if (!bFitsPDF)
+		{
+			//check if it belongs to some of the modes
+			//calculate distance
+			float var = m_modes[pos].variance;
+			float muR = m_modes[pos].muR;
+			float muG = m_modes[pos].muG;
+			float muB = m_modes[pos].muB;
+		
+			float dR=muR - pixel(0);
+			float dG=muG - pixel(1);
+			float dB=muB - pixel(2);
+
+			// calculate the squared distance
+			float dist = (dR*dR + dG*dG + dB*dB);
+
+			if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+				bBackgroundHigh = true;
+			
+			// a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
+			if(dist < m_params.LowThreshold()*var)
+			{
+				bFitsPDF=true;
+
+				// check if this Gaussian is part of the background model
+				if(iModes < backgroundGaussians) 
+					bBackgroundLow = true;
+
+				//update distribution
+				float k = m_params.Alpha()/weight;
+				weight = fOneMinAlpha*weight + m_params.Alpha();
+				m_modes[pos].weight = weight;
+				m_modes[pos].muR = muR - k*(dR);
+				m_modes[pos].muG = muG - k*(dG);
+				m_modes[pos].muB = muB - k*(dB);
+
+				//limit the variance
+				float sigmanew = var + k*(dist-var);
+				m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew;
+				m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+			}
+			else
+			{
+				weight = fOneMinAlpha*weight;
+				if (weight < 0.0)
+				{
+					weight=0.0;
+					numModes--;
+				}
+
+				m_modes[pos].weight = weight;
+				m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+			}
+		}
+		else
+		{
+			weight = fOneMinAlpha*weight;
+			if (weight < 0.0)
+			{
+				weight=0.0;
+				numModes--;
+			}
+			m_modes[pos].weight = weight;
+			m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+		}
+
+		totalWeight += weight;
+	}
+
+	// renormalize weights so they add to one
+	double invTotalWeight = 1.0 / totalWeight;
+	for (int iLocal = 0; iLocal < numModes; iLocal++)
+	{
+		m_modes[posPixel + iLocal].weight *= (float)invTotalWeight;
+		m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight 
+																								/ sqrt(m_modes[posPixel + iLocal].variance);
+	}
+
+	// Sort significance values so they are in desending order. 
+	qsort(&m_modes[posPixel],  numModes, sizeof(GMM), compareGMM);
+
+	// make new mode if needed and exit
+	if (!bFitsPDF)
+	{
+		if (numModes < m_params.MaxModes())
+		{
+			numModes++;
+		}
+		else
+		{
+			// the weakest mode will be replaced
+		}
+
+		pos = posPixel + numModes-1;
+		
+		m_modes[pos].muR = pixel.ch[0];
+		m_modes[pos].muG = pixel.ch[1];
+		m_modes[pos].muB = pixel.ch[2];
+		m_modes[pos].variance = m_variance;
+		m_modes[pos].significants = 0;			// will be set below
+
+    if (numModes==1)
+			m_modes[pos].weight = 1;
+		else
+			m_modes[pos].weight = m_params.Alpha();
+
+		//renormalize weights
+		int iLocal;
+		float sum = 0.0;
+		for (iLocal = 0; iLocal < numModes; iLocal++)
+		{
+			sum += m_modes[posPixel+ iLocal].weight;
+		}
+
+		double invSum = 1.0/sum;
+		for (iLocal = 0; iLocal < numModes; iLocal++)
+		{
+			m_modes[posPixel + iLocal].weight *= (float)invSum;
+			m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight 
+																								/ sqrt(m_modes[posPixel + iLocal].variance);
+
+		}
+	}
+
+	// Sort significance values so they are in desending order. 
+	qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM);
+
+	if(bBackgroundLow)
+	{
+		low_threshold = BACKGROUND;
+	}
+	else
+	{
+		low_threshold = FOREGROUND;
+	}
+
+	if(bBackgroundHigh)
+	{
+		high_threshold = BACKGROUND;
+	}
+	else
+	{
+		high_threshold = FOREGROUND;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					(the memory should already be reserved) 
+//					values: 255-foreground, 125-shadow, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void GrimsonGMM::Subtract(int frame_num, const RgbImage& data,  
+														BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+	unsigned char low_threshold, high_threshold;
+	long posPixel;
+
+	// update each pixel of the image
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{		
+			// update model + background subtract
+			posPixel=(r*m_params.Width()+c)*m_params.MaxModes();
+			
+			SubtractPixel(posPixel, data(r,c), m_modes_per_pixel(r,c), low_threshold, high_threshold);
+			
+			low_threshold_mask(r,c) = low_threshold;
+			high_threshold_mask(r,c) = high_threshold;
+
+			m_background(r,c,0) = (unsigned char)m_modes[posPixel].muR;
+			m_background(r,c,1) = (unsigned char)m_modes[posPixel].muG;
+			m_background(r,c,2) = (unsigned char)m_modes[posPixel].muB;
+		}
+	}
+}
+
diff --git a/package_bgs/dp/GrimsonGMM.h b/package_bgs/dp/GrimsonGMM.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d11a286962e37fc4467ec7decda61209f64a4c1
--- /dev/null
+++ b/package_bgs/dp/GrimsonGMM.h
@@ -0,0 +1,150 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* GrimsonGMM.cpp
+*
+* Purpose: Implementation of the Gaussian mixture model (GMM) background 
+*		  		 subtraction described in:
+*	  			 "Adaptive background mixture models for real-time tracking"
+* 						by Chris Stauffer and W.E.L Grimson
+*
+* Author: Donovan Parks, September 2007
+*
+* This code is based on code by Z. Zivkovic's written for his enhanced GMM
+* background subtraction algorithm: 
+*
+*	"Improved adaptive Gausian mixture model for background subtraction"
+*		Z.Zivkovic 
+*		International Conference Pattern Recognition, UK, August, 2004
+*
+*
+* "Efficient Adaptive Density Estimapion per Image Pixel for the 
+*			Task of Background Subtraction"
+*		Z.Zivkovic, F. van der Heijden 
+*		Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+
+Example:
+		Algorithms::BackgroundSubtraction::GrimsonParams params;
+		params.SetFrameSize(width, height);
+		params.LowThreshold() = 3.0f*3.0f;
+		params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+		params.Alpha() = 0.001f;
+		params.MaxModes() = 3;
+
+		Algorithms::BackgroundSubtraction::GrimsonGMM bgs;
+		bgs.Initalize(params);
+******************************************************************************/
+
+#ifndef GRIMSON_GMM_
+#define GRIMSON_GMM_
+
+#include "Bgs.h"
+
+namespace Algorithms
+{
+	namespace BackgroundSubtraction
+	{
+		typedef struct GMMGaussian
+		{
+			float variance;
+			float muR;
+			float muG;
+			float muB;
+			float weight;
+			float significants;		// this is equal to weight / standard deviation and is used to
+														// determine which Gaussians should be part of the background model
+		} GMM;
+
+		// --- User adjustable parameters used by the Grimson GMM BGS algorithm ---
+		class GrimsonParams : public BgsParams
+		{
+		public:
+			float &LowThreshold() { return m_low_threshold; }
+			float &HighThreshold() { return m_high_threshold; }
+
+			float &Alpha() { return m_alpha; }
+			int &MaxModes() { return m_max_modes; }
+
+		private:
+			// Threshold on the squared dist. to decide when a sample is close to an existing 
+			// components. If it is not close to any a new component will be generated. 
+			// Smaller threshold values lead to more generated components and higher threshold values 
+			// lead to a small number of components but they can grow too large.
+			//
+			// It is usual easiest to think of these thresholds as being the number of variances away
+			// from the mean of a pixel before it is considered to be from the foreground.
+			float m_low_threshold;
+			float m_high_threshold;
+
+			// alpha - speed of update - if the time interval you want to average over is T
+			// set alpha=1/T. 
+			float m_alpha;
+
+			// Maximum number of modes (Gaussian components) that will be used per pixel
+			int m_max_modes;
+		};
+
+		// --- Grimson GMM BGS algorithm ---
+		class GrimsonGMM : public Bgs
+		{
+		public:
+			GrimsonGMM();
+			~GrimsonGMM();
+
+			void Initalize(const BgsParams& param);
+
+			void InitModel(const RgbImage& data);
+			void Subtract(int frame_num, const RgbImage& data,  
+											BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+			void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+			RgbImage* Background();
+
+		private:	
+			void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, 
+													unsigned char& lowThreshold, unsigned char& highThreshold);
+
+			// User adjustable parameters
+			GrimsonParams m_params;
+
+			// Threshold when the component becomes significant enough to be included into
+			// the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
+			// For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+			// it is considered foreground
+			float m_bg_threshold; //1-cf from the paper
+
+			// Initial variance for the newly generated components. 
+			// It will will influence the speed of adaptation. A good guess should be made. 
+			// A simple way is to estimate the typical standard deviation from the images.
+			float m_variance;
+
+			// Dynamic array for the mixture of Gaussians
+			GMM* m_modes;
+
+			// Number of Gaussian components per pixel
+			BwImage m_modes_per_pixel;
+
+			// Current background model
+			RgbImage m_background;
+		};
+	};
+};
+
+#endif
diff --git a/package_bgs/dp/Image.cpp b/package_bgs/dp/Image.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f00febda47ff02b170ddbed9e9d5ed9bf1d4214e
--- /dev/null
+++ b/package_bgs/dp/Image.cpp
@@ -0,0 +1,76 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Image.hpp
+*
+* Purpose:  C++ wrapper for OpenCV IplImage which supports simple and 
+*						efficient access to the image data
+*
+* Author: Donovan Parks, September 2007
+*
+* Based on code from: 
+*  http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.hpptml
+******************************************************************************/
+
+#include "Image.h"
+
+ImageBase::~ImageBase()
+{ 
+  if(imgp != NULL && m_bReleaseMemory)
+    cvReleaseImage(&imgp);
+  imgp = NULL;	
+}
+
+void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue)
+{
+  for(int r = 1; r < image.Ptr()->height-1; ++r)
+  {
+    for(int c = 1; c < image.Ptr()->width-1; ++c)
+    {
+      int count = 0;
+      if(image(r,c) == fgValue)
+      {
+        if(image(r-1,c-1) == fgValue)
+          count++;
+        if(image(r-1,c) == fgValue)
+          count++;
+        if(image(r-1,c+1) == fgValue)
+          count++;
+        if(image(r,c-1) == fgValue)
+          count++;
+        if(image(r,c+1) == fgValue)
+          count++;
+        if(image(r+1,c-1) == fgValue)
+          count++;
+        if(image(r+1,c) == fgValue)
+          count++;
+        if(image(r+1,c+1) == fgValue)
+          count++;
+
+        if(count < minDensity)
+          filtered(r,c) = 0;
+        else
+          filtered(r,c) = fgValue;
+      }
+      else
+      {
+        filtered(r,c) = 0;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/dp/Image.h b/package_bgs/dp/Image.h
new file mode 100644
index 0000000000000000000000000000000000000000..40d327b2fec50d685e3562f8720f46f7484490f6
--- /dev/null
+++ b/package_bgs/dp/Image.h
@@ -0,0 +1,364 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* Image.h
+*
+* Purpose:  C++ wrapper for OpenCV IplImage which supports simple and 
+*						efficient access to the image data
+*
+* Author: Donovan Parks, September 2007
+*
+* Based on code from: 
+*  http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html
+******************************************************************************/
+
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+#include <cv.h>
+#include <cxcore.h>
+
+// --- Image Iterator ---------------------------------------------------------
+
+template <class T>
+class ImageIterator 
+{
+public: 
+  ImageIterator(IplImage* image, int x=0, int y=0, int dx= 0, int dy=0) :
+    i(x), j(y), i0(0) 
+  {    
+    data = reinterpret_cast<T*>(image->imageData);
+    step = image->widthStep / sizeof(T);
+
+    nl= image->height;
+    if ((y+dy)>0 && (y+dy) < nl) 
+      nl= y+dy;
+
+    if (y<0) 
+      j=0;
+
+    data += step*j;
+
+    nc = image->width;
+    if ((x+dx) > 0 && (x+dx) < nc) 
+      nc = x+dx;
+
+    nc *= image->nChannels;
+    if (x>0) 
+      i0 = x*image->nChannels;
+    i = i0;
+
+    nch = image->nChannels;
+  }
+
+
+  /* has next ? */
+  bool operator!() const { return j < nl; }
+
+  /* next pixel */
+  ImageIterator& operator++() 
+  {
+    i++;
+    if (i >= nc) 
+    { 
+      i=i0; 
+      j++; 
+      data += step; 
+    }
+    return *this;
+  }
+
+  ImageIterator& operator+=(int s) 
+  {
+    i+=s;
+    if (i >= nc) 
+    { 
+      i=i0; 
+      j++; 
+      data += step; 
+    }
+    return *this;
+  }
+
+  /* pixel access */
+  T& operator*() { return data[i]; }
+
+  const T operator*() const { return data[i]; }
+
+  const T neighbor(int dx, int dy) const
+  { 
+    return *(data+dy*step+i+dx); 
+  }
+
+  T* operator&() const { return data+i; }
+
+  /* current pixel coordinates */
+  int column() const { return i/nch; }
+  int line() const { return j; }
+
+private:
+  int i, i0,j;
+  T* data;
+  int step;
+  int nl, nc;
+  int nch;
+};
+
+// --- Constants --------------------------------------------------------------
+
+const unsigned char NUM_CHANNELS = 3;
+
+// --- Pixel Types ------------------------------------------------------------
+
+class RgbPixel
+{
+public:
+  RgbPixel() {;}
+  RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b)
+  {
+    ch[0] = _r; ch[1] = _g; ch[2] = _b;
+  }
+
+  RgbPixel& operator=(const RgbPixel& rhs)
+  {
+    ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
+    return *this;
+  }
+
+  inline unsigned char& operator()(const int _ch)
+  {
+    return ch[_ch];
+  }
+
+  inline unsigned char operator()(const int _ch) const
+  {
+    return ch[_ch];
+  }
+
+  unsigned char ch[3];
+};
+
+class RgbPixelFloat
+{
+public:
+  RgbPixelFloat() {;}
+  RgbPixelFloat(float _r, float _g, float _b)
+  {
+    ch[0] = _r; ch[1] = _g; ch[2] = _b;
+  }
+
+  RgbPixelFloat& operator=(const RgbPixelFloat& rhs)
+  {
+    ch[0] = rhs.ch[0]; ch[1] = rhs.ch[1]; ch[2] = rhs.ch[2];
+    return *this;
+  }
+
+  inline float& operator()(const int _ch)
+  {
+    return ch[_ch];
+  }
+
+  inline float operator()(const int _ch) const
+  {
+    return ch[_ch];
+  }
+
+  float ch[3];
+};
+
+// --- Image Types ------------------------------------------------------------
+
+class ImageBase
+{
+public:
+  ImageBase(IplImage* img = NULL) { imgp = img; m_bReleaseMemory = true; }
+  ~ImageBase();
+
+  void ReleaseMemory(bool b) { m_bReleaseMemory = b; }
+
+  IplImage* Ptr() { return imgp; }
+  const IplImage* Ptr() const { return imgp; }
+
+  void ReleaseImage()
+  {
+    cvReleaseImage(&imgp);
+  }
+
+  void operator=(IplImage* img) 
+  { 
+    imgp = img;
+  }
+
+  // copy-constructor
+  ImageBase(const ImageBase& rhs)
+  {	
+    // it is very inefficent if this copy-constructor is called
+    assert(false);
+  }
+
+  // assignment operator
+  ImageBase& operator=(const ImageBase& rhs)
+  {
+    // it is very inefficent if operator= is called
+    assert(false);
+
+    return *this;
+  }
+
+  virtual void Clear() = 0;
+
+protected:
+  IplImage* imgp;
+  bool m_bReleaseMemory;
+};
+
+class RgbImage : public ImageBase
+{
+public:
+  RgbImage(IplImage* img = NULL) : ImageBase(img) { ; }
+
+  virtual void Clear()
+  {
+    cvZero(imgp);
+  }
+
+  void operator=(IplImage* img) 
+  { 
+    imgp = img;
+  }
+
+  // channel-level access using image(row, col, channel)
+  inline unsigned char& operator()(const int r, const int c, const int ch)
+  {
+    return (unsigned char &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels+ch];
+  }
+
+  inline const unsigned char& operator()(const int r, const int c, const int ch) const
+  {
+    return (unsigned char &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels+ch];
+  }
+
+  // RGB pixel-level access using image(row, col)
+  inline RgbPixel& operator()(const int r, const int c) 
+  {
+    return (RgbPixel &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels];
+  }
+
+  inline const RgbPixel& operator()(const int r, const int c) const
+  {
+    return (RgbPixel &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels];
+  }
+};
+
+class RgbImageFloat : public ImageBase
+{
+public:
+  RgbImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
+
+  virtual void Clear()
+  {
+    cvZero(imgp);
+  }
+
+  void operator=(IplImage* img) 
+  { 
+    imgp = img;
+  }
+
+  // channel-level access using image(row, col, channel)
+  inline float& operator()(const int r, const int c, const int ch)
+  {
+    return (float &)imgp->imageData[r*imgp->widthStep+(c*imgp->nChannels+ch)*sizeof(float)];
+  }
+
+  inline float operator()(const int r, const int c, const int ch) const
+  {
+    return (float)imgp->imageData[r*imgp->widthStep+(c*imgp->nChannels+ch)*sizeof(float)];
+  }
+
+  // RGB pixel-level access using image(row, col)
+  inline RgbPixelFloat& operator()(const int r, const int c) 
+  {
+    return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels*sizeof(float)];
+  }
+
+  inline const RgbPixelFloat& operator()(const int r, const int c) const
+  {
+    return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels*sizeof(float)];
+  }
+};
+
+class BwImage : public ImageBase
+{
+public:
+  BwImage(IplImage* img = NULL) : ImageBase(img) { ; }
+
+  virtual void Clear()
+  {
+    cvZero(imgp);
+  }
+
+  void operator=(IplImage* img) 
+  { 
+    imgp = img;
+  }
+
+  // pixel-level access using image(row, col)
+  inline unsigned char& operator()(const int r, const int c)
+  {
+    return (unsigned char &)imgp->imageData[r*imgp->widthStep+c];
+  }
+
+  inline unsigned char operator()(const int r, const int c) const
+  {
+    return (unsigned char)imgp->imageData[r*imgp->widthStep+c];
+  }
+};
+
+class BwImageFloat : public ImageBase
+{
+public:
+  BwImageFloat(IplImage* img = NULL) : ImageBase(img) { ; }
+
+  virtual void Clear()
+  {
+    cvZero(imgp);
+  }
+
+  void operator=(IplImage* img) 
+  { 
+    imgp = img;
+  }
+
+  // pixel-level access using image(row, col)
+  inline float& operator()(const int r, const int c)
+  {
+    return (float &)imgp->imageData[r*imgp->widthStep+c*sizeof(float)];
+  }
+
+  inline float operator()(const int r, const int c) const
+  {
+    return (float)imgp->imageData[r*imgp->widthStep+c*sizeof(float)];
+  }
+};
+
+// --- Image Functions --------------------------------------------------------
+
+void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue);
+
+#endif
\ No newline at end of file
diff --git a/package_bgs/dp/MeanBGS.cpp b/package_bgs/dp/MeanBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b8df8958dec2e8fd1a0735861134be91b3b7d25e
--- /dev/null
+++ b/package_bgs/dp/MeanBGS.cpp
@@ -0,0 +1,131 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* MeanBGS.h
+*
+* Purpose: Implementation of a simple temporal mean background 
+*		  		 subtraction algorithm.
+*
+* Author: Donovan Parks, September 2007
+*
+******************************************************************************/
+
+#include "MeanBGS.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+void MeanBGS::Initalize(const BgsParams& param)
+{
+	m_params = (MeanParams&)param;
+
+	m_mean = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_32F, 3);
+	m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+}
+
+void MeanBGS::InitModel(const RgbImage& data)
+{
+	for (unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+			{
+				m_mean(r,c,ch) = (float)data(r,c,ch);
+			}
+		}
+	}
+}
+
+void MeanBGS::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	// update background model
+	for (unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			// perform conditional updating only if we are passed the learning phase
+			if(update_mask(r,c) == BACKGROUND || frame_num < m_params.LearningFrames())
+			{
+				// update B/G model
+				float mean;
+				for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+				{
+					mean = m_params.Alpha() * m_mean(r,c,ch) + (1.0f-m_params.Alpha()) * data(r,c,ch);
+					m_mean(r,c,ch) = mean;
+					m_background(r,c,ch) = (unsigned char)(mean + 0.5);
+				}
+			}
+		}
+	}
+}
+
+void MeanBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, 
+															unsigned char& low_threshold, 
+															unsigned char& high_threshold)
+{
+	// calculate distance to sample point
+	float dist = 0;
+	for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+	{
+		dist += (pixel(ch)-m_mean(r,c,ch))*(pixel(ch)-m_mean(r,c,ch));
+	}
+
+	// determine if sample point is F/G or B/G pixel
+	low_threshold = BACKGROUND;
+	if(dist > m_params.LowThreshold())
+	{
+		low_threshold = FOREGROUND;
+	}
+
+	high_threshold = BACKGROUND;
+	if(dist > m_params.HighThreshold())
+	{
+		high_threshold = FOREGROUND;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					values: 255-foreground, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void MeanBGS::Subtract(int frame_num, const RgbImage& data, 
+												BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+	unsigned char low_threshold, high_threshold;
+
+	// update each pixel of the image
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{	
+			// perform background subtraction + update background model
+			SubtractPixel(r, c, data(r,c), low_threshold, high_threshold);
+
+			// setup silhouette mask
+			low_threshold_mask(r,c) = low_threshold;
+			high_threshold_mask(r,c) = high_threshold;
+		}
+	}
+}
+
+
+
+
diff --git a/package_bgs/dp/MeanBGS.h b/package_bgs/dp/MeanBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..881beb70fcdb6796aff3039f8dec8d1282c2bf86
--- /dev/null
+++ b/package_bgs/dp/MeanBGS.h
@@ -0,0 +1,98 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* MeanBGS.hpp
+*
+* Purpose: Implementation of a simple temporal mean background 
+*		  		 subtraction algorithm.
+*
+* Author: Donovan Parks, September 2007
+*
+
+Example:
+Algorithms::BackgroundSubtraction::MeanParams params;
+params.SetFrameSize(width, height);
+params.LowThreshold() = 3*30*30;
+params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+params.Alpha() = 1e-6f;
+params.LearningFrames() = 30;
+
+Algorithms::BackgroundSubtraction::MeanBGS bgs;
+bgs.Initalize(params);
+******************************************************************************/
+
+#include "Bgs.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+
+    // --- Parameters used by the Mean BGS algorithm ---
+    class MeanParams : public BgsParams
+    {
+    public:
+      unsigned int &LowThreshold() { return m_low_threshold; }
+      unsigned int &HighThreshold() { return m_high_threshold; }
+
+      float &Alpha() { return m_alpha; }
+      int &LearningFrames() { return m_learning_frames; }
+
+    private:
+      // A pixel is considered to be from the background if the squared distance between 
+      // it and the background model is less than the threshold.
+      unsigned int m_low_threshold;
+      unsigned int m_high_threshold;
+
+      float m_alpha;
+      int m_learning_frames;
+    };
+
+
+    // --- Mean BGS algorithm ---
+    class MeanBGS : public Bgs
+    {
+    public:
+      virtual ~MeanBGS() {}
+
+      void Initalize(const BgsParams& param);
+
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data,  
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+      RgbImage* Background() { return &m_background; }
+
+    private:	
+      void SubtractPixel(int r, int c, const RgbPixel& pixel, 
+        unsigned char& lowThreshold, unsigned char& highThreshold);
+
+      MeanParams m_params;
+
+      RgbImageFloat m_mean;
+      RgbImage m_background;
+    };
+
+  };
+};
+
+
+
+
+
diff --git a/package_bgs/dp/PratiMediodBGS.cpp b/package_bgs/dp/PratiMediodBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ef44c0f5a71314e7ee799e987f2b0b74014ce8d
--- /dev/null
+++ b/package_bgs/dp/PratiMediodBGS.cpp
@@ -0,0 +1,276 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* PratiMediodBGS.h
+*
+* Purpose: Implementation of the temporal median background 
+*		  		 subtraction algorithm described in:
+*
+* [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream"
+* 			by R. Cucchiara et al (2003)
+*
+* [2] "Reliable Background Suppression for Complex Scenes"
+*				by S. Calderara et al (2006)
+*
+* Author: Donovan Parks, September 2007
+*
+* Please note that this is not an implementation of the complete system 
+* given in the above papers. It simply implements the temporal media background
+* subtraction algorithm.
+******************************************************************************/
+
+#include "PratiMediodBGS.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+PratiMediodBGS::PratiMediodBGS()
+{
+	m_median_buffer = NULL;
+}
+
+PratiMediodBGS::~PratiMediodBGS()
+{
+	if(m_median_buffer != NULL)
+		delete[] m_median_buffer;
+}
+
+void PratiMediodBGS::Initalize(const BgsParams& param)
+{
+	m_params = (PratiParams&)param;
+
+	m_mask_low_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
+	m_mask_high_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
+
+	m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+
+	m_median_buffer = new MEDIAN_BUFFER[m_params.Size()];
+}
+
+void PratiMediodBGS::InitModel(const RgbImage& data)
+{
+	// there is no need to initialize the mode since it needs a buffer of frames
+	// before it can performing background subtraction
+}
+
+void PratiMediodBGS::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	// update the image buffer with the new frame and calculate new median values
+	if(frame_num % m_params.SamplingRate() == 0)
+	{
+		if(m_median_buffer[0].dist.size() == m_params.HistorySize())
+		{
+			// subtract distance to sample being removed from all distances
+			for(unsigned int r = 0; r < m_params.Height(); ++r)
+			{
+				for(unsigned int c = 0; c < m_params.Width(); ++c)
+				{	
+					int i = r*m_params.Width()+c;
+
+					if(update_mask(r,c) == BACKGROUND)
+					{
+						int oldPos = m_median_buffer[i].pos;
+						for(unsigned int s = 0; s < m_median_buffer[i].pixels.size(); ++s)
+						{
+							int maxDist = 0;
+							for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+							{
+								int tempDist = abs(m_median_buffer[i].pixels.at(oldPos)(ch) 
+																		- m_median_buffer[i].pixels.at(s)(ch));
+								if(tempDist > maxDist)
+									maxDist = tempDist;
+							}
+
+							m_median_buffer[i].dist.at(s) -= maxDist;
+						}
+				
+						int dist;
+						UpdateMediod(r, c, data, dist);
+						m_median_buffer[i].dist.at(oldPos) = dist;
+						m_median_buffer[i].pixels.at(oldPos) = data(r,c);
+						m_median_buffer[i].pos++;
+						if(m_median_buffer[i].pos >= m_params.HistorySize())
+							m_median_buffer[i].pos = 0;
+					}
+				}
+			}
+		}
+		else
+		{
+			// calculate sum of L-inf distances for new point and 
+			// add distance from each sample point to this point to their L-inf sum
+			int dist;
+			for(unsigned int r = 0; r < m_params.Height(); ++r)
+			{
+				for(unsigned int c = 0; c < m_params.Width(); ++c)
+				{	
+					int index = r*m_params.Width()+c;
+					UpdateMediod(r, c, data, dist);
+					m_median_buffer[index].dist.push_back(dist);
+					m_median_buffer[index].pos = 0;
+					m_median_buffer[index].pixels.push_back(data(r,c)); 
+				}
+			}
+		}
+	}
+}
+
+void PratiMediodBGS::UpdateMediod(int r, int c, const RgbImage& new_frame, int& dist)
+{
+	// calculate sum of L-inf distances for new point and 
+	// add distance from each sample point to this point to their L-inf sum
+	unsigned int i = (r*m_params.Width()+c);
+
+	m_median_buffer[i].medianDist = INT_MAX;
+
+	int L_inf_dist = 0;
+	for(unsigned int s = 0; s < m_median_buffer[i].dist.size(); ++s)
+	{
+		int maxDist = 0;
+		for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+		{
+			int tempDist = abs(m_median_buffer[i].pixels.at(s)(ch) - new_frame(r,c,ch));
+			if(tempDist > maxDist)
+				maxDist = tempDist;
+		}
+
+		// check if point from this frame in the image buffer is the median
+		m_median_buffer[i].dist.at(s) += maxDist;
+		if(m_median_buffer[i].dist.at(s) < m_median_buffer[i].medianDist)
+		{
+			m_median_buffer[i].medianDist = m_median_buffer[i].dist.at(s);
+			m_median_buffer[i].median = m_median_buffer[i].pixels.at(s);
+		}
+
+		L_inf_dist += maxDist;
+	}
+
+	dist = L_inf_dist;
+
+	// check if the new point is the median
+	if(L_inf_dist < m_median_buffer[i].medianDist)
+	{
+		m_median_buffer[i].medianDist = L_inf_dist;
+		m_median_buffer[i].median = new_frame(r,c);
+	}
+}
+
+void PratiMediodBGS::Combine(const BwImage& low_mask, const BwImage& high_mask, BwImage& output)
+{
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			output(r,c) = BACKGROUND;
+
+			if(r == 0 || c == 0 || r == m_params.Height()-1 || c == m_params.Width()-1)
+				continue;	
+			
+			if(high_mask(r,c) == FOREGROUND)
+			{
+				output(r,c) = FOREGROUND;
+			}
+			else if(low_mask(r,c) == FOREGROUND)
+			{
+				// consider the pixel to be a F/G pixel if it is 8-connected to
+				// a F/G pixel in the high mask
+				// check if there is an 8-connected foreground pixel
+				if(high_mask(r-1,c-1))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r-1,c))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r-1,c+1))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r,c-1))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r,c+1))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r+1,c-1))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r+1,c))	
+					output(r,c) = FOREGROUND;
+				else if(high_mask(r+1,c+1))	
+					output(r,c) = FOREGROUND;
+			}
+		}
+	}
+}
+
+void PratiMediodBGS::CalculateMasks(int r, int c, const RgbPixel& pixel)
+{
+	int pos = r*m_params.Width()+c;
+
+	// calculate l-inf distance between current value and median value
+	unsigned char dist = 0;
+	for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+	{
+		int tempDist = abs(pixel(ch) - m_median_buffer[pos].median(ch));
+		if(tempDist > dist)
+			dist = tempDist;
+	}
+	m_background(r,c) = m_median_buffer[pos].median;
+
+	// check if pixel is a B/G or F/G pixel according to the low threshold B/G model
+	m_mask_low_threshold(r,c) = BACKGROUND;
+	if(dist > m_params.LowThreshold())
+	{
+		m_mask_low_threshold(r,c) = FOREGROUND;
+	}
+
+	// check if pixel is a B/G or F/G pixel according to the high threshold B/G model
+	m_mask_high_threshold(r,c)= BACKGROUND;
+	if(dist > m_params.HighThreshold())
+	{
+		m_mask_high_threshold(r,c) = FOREGROUND;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					values: 255-foreground, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void PratiMediodBGS::Subtract(int frame_num, const RgbImage& data, 
+																BwImage& low_threshold_mark, BwImage& high_threshold_mark)
+{
+	if(frame_num < m_params.HistorySize())
+	{
+		low_threshold_mark.Clear();
+		high_threshold_mark.Clear();
+		return;
+	}
+
+	// update each pixel of the image
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{	
+			// need at least one frame of data before we can start calculating the masks
+			CalculateMasks(r, c, data(r,c));
+		}
+	}
+
+	// combine low and high threshold masks
+	Combine(m_mask_low_threshold, m_mask_high_threshold, low_threshold_mark);
+	Combine(m_mask_low_threshold, m_mask_high_threshold, high_threshold_mark);
+}
+
+
+
+
diff --git a/package_bgs/dp/PratiMediodBGS.h b/package_bgs/dp/PratiMediodBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b373d7c45f49c28b3c7c04cacfd9e222b998bef
--- /dev/null
+++ b/package_bgs/dp/PratiMediodBGS.h
@@ -0,0 +1,142 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* PratiMediodBGS.hpp
+*
+* Purpose: Implementation of the temporal median background 
+*		  		 subtraction algorithm described in:
+*
+* [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream"
+* 			by R. Cucchiara et al (2003)
+*
+* [2] "Reliable Background Suppression for Complex Scenes"
+*				by S. Calderara et al (2006)
+*
+* Author: Donovan Parks, September 2007
+*
+* Please note that this is not an implementation of the complete system 
+* given in the above papers. It simply implements the temporal media background
+* subtraction algorithm.
+
+Example:
+Algorithms::BackgroundSubtraction::PratiParams params;
+params.SetFrameSize(width, height);
+params.LowThreshold() = 30;
+params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+params.SamplingRate() = 5;
+params.HistorySize() = 16;
+params.Weight() = 5;
+
+Algorithms::BackgroundSubtraction::PratiMediodBGS bgs;
+bgs.Initalize(params);
+******************************************************************************/
+
+#ifndef PRATI_MEDIA_BGS_H
+#define PRATI_MEDIA_BGS_H
+
+#include <vector>
+#include "Bgs.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    // --- Parameters used by the Prati Mediod BGS algorithm ---
+    class PratiParams : public BgsParams
+    {
+    public:
+      unsigned int &LowThreshold() { return m_low_threshold; }
+      unsigned int &HighThreshold() { return m_high_threshold; }
+
+      int &Weight() { return m_weight; }
+      int &SamplingRate() { return m_sampling_rate; }
+      int &HistorySize() { return m_history_size; }
+
+    private:
+      // The low threshold is used to supress noise. The high thresohld is used 
+      // to find pixels highly likely to be foreground. This implementation uses an L-inf 
+      // distance measure and a pixel p is considered F/G if D(I(p), B(p)) > threshold. 
+      // The two threshold maps are combined as in [2].
+      unsigned int m_low_threshold;
+      unsigned int m_high_threshold;
+
+      // The weight parameter controls the amount of influence given to previous background samples
+      // see w_b in equation (2) of [1]
+      // in [2] this value is set to 1
+      int m_weight;
+
+      // Number of samples to consider when calculating temporal mediod value
+      int m_history_size;
+
+      // Rate at which to obtain new samples
+      int m_sampling_rate;
+    };
+
+    // --- Prati Mediod BGS algorithm ---
+    class PratiMediodBGS : public Bgs 
+    {
+    private:	
+      // sum of L-inf distances from a sample point to all other sample points
+      struct MEDIAN_BUFFER
+      {
+        std::vector<RgbPixel> pixels;		// vector of pixels at give location in image
+        std::vector<int> dist;					// distance from pixel to all other pixels
+        int pos;												// current position in circular buffer
+
+        RgbPixel median;								// median at this pixel location
+        int medianDist;									// distance from median pixel to all other pixels
+      };
+
+    public:
+      PratiMediodBGS();
+      ~PratiMediodBGS();
+
+      void Initalize(const BgsParams& param);
+
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data,  
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+      RgbImage* Background() { return &m_background; }
+
+    private:	
+      MEDIAN_BUFFER* m_median_buffer;
+
+      void CalculateMasks(int r, int c, const RgbPixel& pixel);
+      void Combine(const BwImage& low_mask, const BwImage& high_mask, BwImage& output);
+      void UpdateMediod(int r, int c, const RgbImage& new_frame, int& dist);
+
+      PratiParams m_params;
+
+      RgbImage m_background;
+
+      BwImage m_mask_low_threshold;
+      BwImage m_mask_high_threshold;
+    };
+
+  };
+};
+
+#endif
+
+
+
+
+
+
diff --git a/package_bgs/dp/TextureBGS.cpp b/package_bgs/dp/TextureBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7ccac3715b782809f966155a317a529717a5c311
--- /dev/null
+++ b/package_bgs/dp/TextureBGS.cpp
@@ -0,0 +1,153 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "TextureBGS.h"
+
+TextureBGS::TextureBGS(){}
+TextureBGS::~TextureBGS(){}
+
+void TextureBGS::LBP(RgbImage& image, RgbImage& texture)
+{
+  for(int y = TEXTURE_R; y < image.Ptr()->height-TEXTURE_R; ++y)
+  {
+    for(int x = TEXTURE_R; x < image.Ptr()->width-TEXTURE_R; ++x)
+    {		
+      for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+      {
+        unsigned char textureCode = 0;
+        int centerValue = (int)image(y, x, ch);
+
+        // this only works for a texture radius of 2
+        if(centerValue - (int)image(y-2, x, ch) + HYSTERSIS >= 0)
+          textureCode += 1;
+
+        if(centerValue - (int)image(y-1, x-2, ch) + HYSTERSIS >= 0)
+          textureCode += 2;
+
+        if(centerValue - (int)image(y-1, x+2, ch) + HYSTERSIS >= 0)
+          textureCode += 4;
+
+        if(centerValue - (int)image(y+1, x-2, ch) + HYSTERSIS >= 0)
+          textureCode += 8;
+
+        if(centerValue - (int)image(y+1, x+2, ch) + HYSTERSIS >= 0)
+          textureCode += 16;
+
+        if(centerValue - (int)image(y+2, x, ch) + HYSTERSIS >= 0)
+          textureCode += 32;
+
+        texture(y,x,ch) = textureCode;
+      }
+    }
+  }
+}
+
+void TextureBGS::Histogram(RgbImage& texture, TextureHistogram* curTextureHist)
+{
+  // calculate histogram within a 2*REGION_R square
+  for(int y = REGION_R+TEXTURE_R; y < texture.Ptr()->height-REGION_R-TEXTURE_R; ++y)
+  {
+    for(int x = REGION_R+TEXTURE_R; x < texture.Ptr()->width-REGION_R-TEXTURE_R; ++x)
+    {	
+      int index = x+y*(texture.Ptr()->width);
+
+      // clear histogram
+      for(int i = 0; i < NUM_BINS; ++i)
+      {
+        curTextureHist[index].r[i] = 0;
+        curTextureHist[index].g[i] = 0;
+        curTextureHist[index].b[i] = 0;
+      }
+
+      // calculate histogram
+      for(int j = -REGION_R; j <= REGION_R; ++j)
+      {
+        for(int i = -REGION_R; i <= REGION_R; ++i)
+        {
+          curTextureHist[index].r[texture(y+j,x+i,2)]++;
+          curTextureHist[index].g[texture(y+j,x+i,1)]++;
+          curTextureHist[index].b[texture(y+j,x+i,0)]++;
+        }
+      }
+    }
+  }
+}
+
+int TextureBGS::ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist)
+{
+  int proximity = 0;	
+  for(int i = 0; i < NUM_BINS; ++i)
+  {
+    proximity += std::min(bgTexture.r[i], curTextureHist.r[i]);
+    proximity += std::min(bgTexture.g[i], curTextureHist.g[i]);
+    proximity += std::min(bgTexture.b[i], curTextureHist.b[i]);
+  }
+
+  return proximity;	
+}
+
+void TextureBGS::BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, 
+                unsigned char* modeArray, float threshold, BwImage& fgMask)
+{
+  cvZero(fgMask.Ptr());
+
+  for(int y = REGION_R+TEXTURE_R; y < fgMask.Ptr()->height-REGION_R-TEXTURE_R; ++y)
+  {
+    for(int x = REGION_R+TEXTURE_R; x < fgMask.Ptr()->width-REGION_R-TEXTURE_R; ++x)
+    {	
+      int index = x+y*(fgMask.Ptr()->width);
+
+      // find closest matching texture in background model
+      int maxProximity = -1;
+
+      for(int m = 0; m < NUM_MODES; ++m)
+      {
+        int proximity = ProximityMeasure(bgModel[index].mode[m], curTextureHist[index]);
+
+        if(proximity > maxProximity)
+        {
+          maxProximity = proximity;
+          modeArray[index] = m;
+        }
+      }
+
+      if(maxProximity < threshold)
+        fgMask(y,x) = 255;
+    }
+  }
+}
+
+void TextureBGS::UpdateModel(BwImage& fgMask, TextureArray* bgModel, 
+                 TextureHistogram* curTextureHist, unsigned char* modeArray)
+{
+  for(int y = REGION_R+TEXTURE_R; y < fgMask.Ptr()->height-REGION_R-TEXTURE_R; ++y)
+  {
+    for(int x = REGION_R+TEXTURE_R; x < fgMask.Ptr()->width-REGION_R-TEXTURE_R; ++x)
+    {		
+      int index = x+y*(fgMask.Ptr()->width);
+
+      if(fgMask(x,y) == 0)
+      {
+        for(int i = 0; i < NUM_BINS; ++i)
+        {
+          bgModel[index].mode[modeArray[index]].r[i]
+          = (unsigned char)(ALPHA*curTextureHist[index].r[i]
+          + (1-ALPHA)*bgModel[index].mode[modeArray[index]].r[i] + 0.5);
+        }
+      }				
+    }
+  }	
+}
diff --git a/package_bgs/dp/TextureBGS.h b/package_bgs/dp/TextureBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..573e6f9af7992833f310dba72aa9a4e5e72bc771
--- /dev/null
+++ b/package_bgs/dp/TextureBGS.h
@@ -0,0 +1,55 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <math.h>
+#include "Image.h"
+
+const int REGION_R = 5;			// Note: the code currently assumes this value is <= 7
+const int TEXTURE_POINTS = 6;	// Note: the code currently assumes this value is 6
+const int TEXTURE_R = 2;		// Note: the code currently assumes this value is 2
+const int NUM_BINS = 64;		// 2^TEXTURE_POINTS
+const int HYSTERSIS = 3;
+const double ALPHA = 0.05f;
+const double THRESHOLD = 0.5*(REGION_R+REGION_R+1)*(REGION_R+REGION_R+1)*NUM_CHANNELS;
+const int NUM_MODES = 1;		// The paper describes how multiple modes can be maintained,
+// but this implementation does not fully support more than one
+
+struct TextureHistogram
+{
+  unsigned char r[NUM_BINS];	// histogram for red channel
+  unsigned char g[NUM_BINS];	// histogram for green channel
+  unsigned char b[NUM_BINS];	// histogram for blue channel
+};
+
+struct TextureArray
+{
+  TextureHistogram mode[NUM_MODES];
+};
+
+class TextureBGS
+{
+public:
+  TextureBGS();
+  ~TextureBGS();
+
+  void LBP(RgbImage& image, RgbImage& texture);
+  void Histogram(RgbImage& texture, TextureHistogram* curTextureHist);
+  int ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist);
+  void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, 
+                unsigned char* modeArray, float threshold, BwImage& fgMask);
+  void UpdateModel(BwImage& fgMask, TextureArray* bgModel, 
+                 TextureHistogram* curTextureHist, unsigned char* modeArray);
+};
diff --git a/package_bgs/dp/WrenGA.cpp b/package_bgs/dp/WrenGA.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ae10dd9cb93626827d2b8e86d14857c50e8a768
--- /dev/null
+++ b/package_bgs/dp/WrenGA.cpp
@@ -0,0 +1,174 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* WrenGA.h
+*
+* Purpose: Implementation of the running Gaussian average background 
+*		  		 subtraction algorithm described in:
+*	  			 "Pfinder: real-time tracking of the human body"
+* 						by C. Wren et al (1997)
+*
+* Author: Donovan Parks, September 2007
+*
+* Please note that this is not an implementation of Pfinder. It implements
+* a simple background subtraction algorithm where each pixel is represented
+* by a single Gaussian and update using a simple weighting function.
+******************************************************************************/
+
+#include "WrenGA.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+WrenGA::WrenGA()
+{
+	m_gaussian = NULL;
+}
+
+WrenGA::~WrenGA()
+{
+	if(m_gaussian != NULL)
+		delete[] m_gaussian;
+}
+
+void WrenGA::Initalize(const BgsParams& param)
+{
+	m_params = (WrenParams&)param;
+
+	m_variance = 36.0f;
+
+	// GMM for each pixel
+	m_gaussian = new GAUSSIAN[m_params.Size()];
+	for(unsigned int i = 0; i < m_params.Size(); ++i)
+	{
+		for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+		{
+			m_gaussian[i].mu[ch] = 0;
+			m_gaussian[i].var[ch] = 0;
+		}
+	}
+
+	m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+}
+
+void WrenGA::InitModel(const RgbImage& data)
+{
+	int pos = 0;
+
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+			{	
+				m_gaussian[pos].mu[ch] = data(r,c,ch);
+				m_gaussian[pos].var[ch] = m_variance;
+			}
+
+			pos++;
+		}
+	}
+}
+
+void WrenGA::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	int pos = 0;
+
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			// perform conditional updating only if we are passed the learning phase
+			if(update_mask(r,c) == BACKGROUND || frame_num < m_params.LearningFrames())
+			{
+				float dR = m_gaussian[pos].mu[0] - data(r,c,0);
+				float dG = m_gaussian[pos].mu[1] - data(r,c,1);
+				float dB = m_gaussian[pos].mu[2] - data(r,c,2);
+
+				float dist = (dR*dR + dG*dG + dB*dB);
+
+				m_gaussian[pos].mu[0] -= m_params.Alpha()*(dR);
+				m_gaussian[pos].mu[1] -= m_params.Alpha()*(dG);
+				m_gaussian[pos].mu[2] -= m_params.Alpha()*(dB);
+
+				float sigmanew = m_gaussian[pos].var[0] + m_params.Alpha()*(dist-m_gaussian[pos].var[0]);
+				m_gaussian[pos].var[0] = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew;
+
+				m_background(r, c, 0) = (unsigned char)(m_gaussian[pos].mu[0] + 0.5);
+				m_background(r, c, 1) = (unsigned char)(m_gaussian[pos].mu[1] + 0.5);
+				m_background(r, c, 2) = (unsigned char)(m_gaussian[pos].mu[2] + 0.5);
+			}
+
+			pos++;
+		}
+	}
+}
+
+void WrenGA::SubtractPixel(int r, int c, const RgbPixel& pixel, 
+															unsigned char& low_threshold, 
+															unsigned char& high_threshold)
+{
+	unsigned int pos = r*m_params.Width()+c;
+
+	// calculate distance between model and pixel
+	float mu[NUM_CHANNELS];
+	float var[1];
+	float delta[NUM_CHANNELS];
+	float dist = 0;
+	for(int ch = 0; ch < NUM_CHANNELS; ++ch)
+	{
+		mu[ch] = m_gaussian[pos].mu[ch];
+		var[0] = m_gaussian[pos].var[0];
+		delta[ch] = mu[ch] - pixel(ch);
+		dist += delta[ch]*delta[ch];
+	}
+
+	// calculate the squared distance and see if pixel fits the B/G model
+	low_threshold = BACKGROUND;
+	high_threshold = BACKGROUND;
+
+	if(dist > m_params.LowThreshold()*var[0])
+		low_threshold = FOREGROUND;
+	if(dist > m_params.HighThreshold()*var[0])
+		high_threshold = FOREGROUND;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					(the memory should already be reserved) 
+//					values: 255-foreground, 125-shadow, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void WrenGA::Subtract(int frame_num, const RgbImage& data, 
+												BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+	unsigned char low_threshold, high_threshold;
+
+	// update each pixel of the image
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			SubtractPixel(r, c, data(r,c), low_threshold, high_threshold);
+			low_threshold_mask(r,c) = low_threshold;
+			high_threshold_mask(r,c) = high_threshold;
+		}
+	}
+}
+
diff --git a/package_bgs/dp/WrenGA.h b/package_bgs/dp/WrenGA.h
new file mode 100644
index 0000000000000000000000000000000000000000..d623e20557fc795dc04ea45478e6030094b16008
--- /dev/null
+++ b/package_bgs/dp/WrenGA.h
@@ -0,0 +1,120 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* WrenGA.hpp
+*
+* Purpose: Implementation of the running Gaussian average background 
+*		  		 subtraction algorithm described in:
+*	  			 "Pfinder: real-time tracking of the human body"
+* 						by C. Wren et al (1997)
+*
+* Author: Donovan Parks, September 2007
+*
+* Please note that this is not an implementation of Pfinder. It implements
+* a simple background subtraction algorithm where each pixel is represented
+* by a single Gaussian and update using a simple weighting function.
+
+Example:
+Algorithms::BackgroundSubtraction::WrenParams params;
+params.SetFrameSize(width, height);
+params.LowThreshold() = 3.5f*3.5f;
+params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+params.Alpha() = 0.005f;
+params.LearningFrames() = 30;
+
+Algorithms::BackgroundSubtraction::WrenGA bgs;
+bgs.Initalize(params);
+******************************************************************************/
+
+#ifndef WREN_GA_H
+#define WREN_GA_H
+
+#include "Bgs.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    // --- Parameters used by the Mean BGS algorithm ---
+    class WrenParams : public BgsParams
+    {
+    public:
+      float &LowThreshold() { return m_low_threshold; }
+      float &HighThreshold() { return m_high_threshold; }
+
+      float &Alpha() { return m_alpha; }
+      int &LearningFrames() { return m_learning_frames; }
+
+    private:
+      // The threshold indicates the number of variances (not standard deviations) away
+      // from the mean before a pixel is considered to be from the foreground.
+      float m_low_threshold;
+      float m_high_threshold;
+
+      float m_alpha;
+      int m_learning_frames;
+    };
+
+
+    // --- Mean BGS algorithm ---
+    class WrenGA : public Bgs
+    {
+    private:	
+      struct GAUSSIAN
+      {
+        float mu[NUM_CHANNELS];
+        float var[NUM_CHANNELS];
+      };
+
+    public:
+      WrenGA();
+      ~WrenGA();
+
+      void Initalize(const BgsParams& param);
+
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data,  
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+      RgbImage* Background() { return &m_background; }
+
+    private:	
+      void SubtractPixel(int r, int c, const RgbPixel& pixel, 
+        unsigned char& lowThreshold, unsigned char& highThreshold);
+
+      WrenParams m_params;
+
+      // Initial variance for the newly generated components. 
+      float m_variance;
+
+      // dynamic array for the mixture of Gaussians
+      GAUSSIAN* m_gaussian;
+
+      RgbImage m_background;
+    };
+  };
+};
+
+#endif
+
+
+
+
+
+
diff --git a/package_bgs/dp/ZivkovicAGMM.cpp b/package_bgs/dp/ZivkovicAGMM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c260132d8b2b85b5669d237ddc6080274b999adb
--- /dev/null
+++ b/package_bgs/dp/ZivkovicAGMM.cpp
@@ -0,0 +1,411 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* ZivkovicAGMM.cpp
+*
+* Purpose: Implementation of the Gaussian mixture model (GMM) background 
+*		  		 subtraction algorithm developed by Z. Zivkovic.
+*
+* Author: Donovan Parks, September 2007
+*
+* This code is based on code by Z. Zivkovic's. I have changed it from a pure
+* C implementation to a cleaner (IMHO) C++ implementation. It is based on the
+* following papers:
+*
+*	"Improved adaptive Gausian mixture model for background subtraction"
+*		Z.Zivkovic 
+*		International Conference Pattern Recognition, UK, August, 2004
+*
+*
+* "Efficient Adaptive Density Estimapion per Image Pixel for the 
+*			Task of Background Subtraction"
+*		Z.Zivkovic, F. van der Heijden 
+*		Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+******************************************************************************/
+
+#include "ZivkovicAGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+ZivkovicAGMM::ZivkovicAGMM()
+{
+	m_modes = NULL;
+	m_modes_per_pixel = NULL;
+}
+
+ZivkovicAGMM::~ZivkovicAGMM()
+{
+	if(m_modes != NULL)
+		delete[] m_modes;
+
+	if(m_modes_per_pixel != NULL)
+		delete[] m_modes_per_pixel;
+}
+
+void ZivkovicAGMM::Initalize(const BgsParams& param)
+{
+	m_params = (ZivkovicParams&)param;
+
+	m_num_bands = 3;							//always 3 - not implemented for other values!
+	m_bg_threshold = 0.75f;				//1-cf from the paper 
+	m_variance = 36.0f;						// variance for the new mode
+	m_complexity_prior = 0.05f;		// complexity reduction prior constant
+
+	// GMM for each pixel
+	m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
+
+	// used modes per pixel
+	m_modes_per_pixel = new unsigned char[m_params.Size()];
+
+	m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+}
+
+void ZivkovicAGMM::InitModel(const RgbImage& data)
+{
+	for(unsigned int i = 0; i < m_params.Size(); ++i)
+	{
+		m_modes_per_pixel[i] = 0;
+	}
+
+	for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+	{
+		m_modes[i].weight = 0;
+		m_modes[i].sigma = 0;
+		m_modes[i].muR = 0;
+		m_modes[i].muG = 0;
+		m_modes[i].muB = 0;
+	}
+}
+
+void ZivkovicAGMM::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+	// it doesn't make sense to have conditional updates in the GMM framework
+}
+
+void ZivkovicAGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char* pModesUsed, 
+																	unsigned char& low_threshold, unsigned char& high_threshold)
+{
+	//calculate distances to the modes (+ sort???)
+	//here we need to go in descending order!!!
+	long pos;
+	bool bFitsPDF=0;
+	bool bBackgroundLow=false;
+	bool bBackgroundHigh=false;
+
+	float fOneMinAlpha = 1-m_params.Alpha();
+
+	float prune = -m_params.Alpha()*m_complexity_prior;
+
+	int nModes =* pModesUsed;
+	float totalWeight = 0.0f;
+
+	// calculate number of Gaussians to include in the background model
+	int backgroundGaussians = 0;
+	double sum = 0.0;
+	for(int i = 0; i < nModes; ++i)
+	{
+		if(sum < m_bg_threshold)
+		{
+			backgroundGaussians++;
+			sum += m_modes[posPixel+i].weight;
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	// update all distributions and check for match with current pixel
+	for (int iModes = 0; iModes < nModes; iModes++)
+	{
+		pos=posPixel+iModes;
+		float weight = m_modes[pos].weight;
+
+		//fit not found yet
+		if (!bFitsPDF)
+		{
+			//check if it belongs to some of the modes
+			//calculate distance
+			float var = m_modes[pos].sigma;
+			float muR = m_modes[pos].muR;
+			float muG = m_modes[pos].muG;
+			float muB = m_modes[pos].muB;
+		
+			float dR=muR - pixel(0);
+			float dG=muG - pixel(1);
+			float dB=muB - pixel(2);
+			
+			// calculate the squared distance
+			float dist = (dR*dR + dG*dG + dB*dB);
+
+			if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+				bBackgroundHigh = true;
+			
+			//check fit
+			if (dist < m_params.LowThreshold()*var)
+			{
+				/////
+				//belongs to the mode
+				bFitsPDF = true;
+
+				// check if this Gaussian is part of the background model
+				if(iModes < backgroundGaussians) 
+					bBackgroundLow = true;
+
+				//update distribution
+				float k = m_params.Alpha()/weight;
+				weight = fOneMinAlpha*weight+prune;
+				weight += m_params.Alpha();
+				m_modes[pos].weight = weight;
+				m_modes[pos].muR = muR - k*(dR);
+				m_modes[pos].muG = muG - k*(dG);
+				m_modes[pos].muB = muB - k*(dB);
+
+				//limit update speed for cov matrice
+				//not needed
+				//k=k>20*m_m_params.Alpha()?20*m_m_params.Alpha():k;
+				//float sigmanew = var + k*((0.33*(dR*dR+dG*dG+dB*dB))-var);
+				//float sigmanew = var + k*((dR*dR+dG*dG+dB*dB)-var);
+				//float sigmanew = var + k*((0.33*dist)-var);
+				float sigmanew = var + k*(dist-var);
+
+				//limit the variance
+				m_modes[pos].sigma = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew;
+
+				// Sort weights so they are in desending order. Note that only the weight for this
+				// mode will increase and that the weight for all modes that were previously larger than
+				// this one have already been modified and will not be modified again. Thus, we just need to 
+				// the correct position of this mode in the already sorted list.
+
+				// Zivkovic implementation has been modified for clarity, but the results are equivalent
+				/*
+				for (int iLocal = iModes;iLocal>0;iLocal--)
+				{
+					long posLocal=posPixel + iLocal;
+					if (weight < (m_modes[posLocal-1].weight))
+					{
+						break;
+					}
+					else
+					{
+						//swap
+						GMM temp = m_modes[posLocal];
+						m_modes[posLocal] = m_modes[posLocal-1];
+						m_modes[posLocal-1] = temp;
+					}
+				}
+				*/
+
+				for (int iLocal = iModes; iLocal > 0; iLocal--)
+				{
+					long posLocal = posPixel + iLocal;
+					if (m_modes[posLocal].weight > m_modes[posLocal-1].weight)
+					{
+						//swap
+						GMM temp = m_modes[posLocal];
+						m_modes[posLocal] = m_modes[posLocal-1];
+						m_modes[posLocal-1] = temp;
+					}
+					else
+					{
+						break;
+					}
+				}
+			}
+			else
+			{
+				weight = fOneMinAlpha*weight+prune;
+				//check prune
+				if (weight < -prune)
+				{
+					weight=0.0;
+					nModes--;
+				}
+				m_modes[pos].weight = weight;
+			}
+			//check if it fits the current mode (2.5 sigma)
+			///////
+		}
+		//fit not found yet
+		/////
+		else
+		{
+			weight = fOneMinAlpha*weight + prune;
+			//check prune
+			if (weight < -prune)
+			{
+				weight=0.0;
+				nModes--;
+			}
+			m_modes[pos].weight = weight;
+		}
+		totalWeight += weight;
+	}
+
+	//renormalize weights so they sum to 1
+	for (int iLocal = 0; iLocal < nModes; iLocal++)
+	{
+		m_modes[posPixel+ iLocal].weight = m_modes[posPixel+ iLocal].weight/totalWeight;
+	}
+	
+	//make new mode if needed and exit
+	if (!bFitsPDF)
+	{
+		if (nModes == m_params.MaxModes())
+		{
+			//replace the weakest
+		}
+		else
+		{
+			nModes++;
+		}
+		pos = posPixel + nModes-1;
+
+    if (nModes==1)
+			m_modes[pos].weight=1;
+		else
+			m_modes[pos].weight=m_params.Alpha();
+
+		// Zivkovic implementation changes as this will not result in the
+		// weights adding to 1
+		/*
+		int iLocal;
+		for (iLocal = 0; iLocal < m_params.MaxModes()odes-1; iLocal++)
+		{
+			m_modes[posPixel+ iLocal].weight *= fOneMinAlpha;
+		}
+		*/
+
+		// Revised implementation:
+		//renormalize weights
+		int iLocal;
+		float sum = 0.0;
+		for (iLocal = 0; iLocal < nModes; iLocal++)
+		{
+			sum += m_modes[posPixel+ iLocal].weight;
+		}
+
+		float invSum = 1.0f/sum;
+		for (iLocal = 0; iLocal < nModes; iLocal++)
+		{
+			m_modes[posPixel+ iLocal].weight *= invSum;
+		}
+
+		m_modes[pos].muR=pixel(0);
+		m_modes[pos].muG=pixel(1);
+		m_modes[pos].muB=pixel(2);
+		m_modes[pos].sigma=m_variance;
+
+		// Zivkovic implementation to sort GMM so they are sorted in descending order according to their weight.
+		// It has been revised for clarity, but the results are equivalent
+		/*
+		for (iLocal = m_params.MaxModes()odes-1; iLocal > 0; iLocal--)
+		{
+			long posLocal = posPixel + iLocal;
+			if (m_params.Alpha() < (m_modes[posLocal-1].weight))
+			{
+				break;
+			}
+			else
+			{
+				//swap
+				GMM temp = m_modes[posLocal];
+				m_modes[posLocal] = m_modes[posLocal-1];
+				m_modes[posLocal-1] = temp;
+			}
+		}
+		*/
+
+		// sort GMM so they are sorted in descending order according to their weight
+		for (iLocal = nModes-1; iLocal > 0; iLocal--)
+		{
+			long posLocal = posPixel + iLocal;
+			if (m_modes[posLocal].weight > m_modes[posLocal-1].weight)
+			{
+				//swap
+				GMM temp = m_modes[posLocal];
+				m_modes[posLocal] = m_modes[posLocal-1];
+				m_modes[posLocal-1] = temp;
+			}
+			else
+			{
+				break;
+			}
+		}
+	}
+
+	//set the number of modes
+	*pModesUsed=nModes;
+
+	if(bBackgroundLow)
+	{
+		low_threshold = BACKGROUND;
+	}
+	else
+	{
+		low_threshold = FOREGROUND;
+	}
+
+	if(bBackgroundHigh)
+	{
+		high_threshold = BACKGROUND;
+	}
+	else
+	{
+		high_threshold = FOREGROUND;
+	}
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					(the memory should already be reserved) 
+//					values: 255-foreground, 125-shadow, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void ZivkovicAGMM::Subtract(int frame_num, const RgbImage& data,  
+															BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+	unsigned char low_threshold, high_threshold;
+
+	// update each pixel of the image
+	long posPixel;
+	unsigned char* pUsedModes=m_modes_per_pixel;
+	for(unsigned int r = 0; r < m_params.Height(); ++r)
+	{
+		for(unsigned int c = 0; c < m_params.Width(); ++c)
+		{
+			//update model+ background subtract
+			posPixel=(r*m_params.Width()+c)*m_params.MaxModes();
+			SubtractPixel(posPixel, data(r,c), pUsedModes, low_threshold, high_threshold);
+			low_threshold_mask(r,c) = low_threshold;
+			high_threshold_mask(r,c) = high_threshold;
+
+			m_background(r,c,0) = (unsigned char)m_modes[posPixel].muR;
+			m_background(r,c,1) = (unsigned char)m_modes[posPixel].muG;
+			m_background(r,c,2) = (unsigned char)m_modes[posPixel].muB;
+
+			pUsedModes++;
+		}
+	}
+}
+
diff --git a/package_bgs/dp/ZivkovicAGMM.h b/package_bgs/dp/ZivkovicAGMM.h
new file mode 100644
index 0000000000000000000000000000000000000000..c58fac424f2f6b83f51e676cc30d14038a67cd44
--- /dev/null
+++ b/package_bgs/dp/ZivkovicAGMM.h
@@ -0,0 +1,160 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* ZivkovicAGMM.hpp
+*
+* Purpose: Implementation of the Gaussian mixture model (GMM) background 
+*		  		 subtraction algorithm developed by Z. Zivkovic.
+*
+* Author: Donovan Parks, September 2007
+*
+* This code is based on code by Z. Zivkovic's. I have changed it from a pure
+* C implementation to a cleaner (IMHO) C++ implementation. It is based on the
+* following papers:
+*
+*	"Improved adaptive Gausian mixture model for background subtraction"
+*		Z.Zivkovic 
+*		International Conference Pattern Recognition, UK, August, 2004
+*
+*
+* "Efficient Adaptive Density Estimapion per Image Pixel for the 
+*			Task of Background Subtraction"
+*		Z.Zivkovic, F. van der Heijden 
+*		Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006.
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+
+Example:
+Algorithms::BackgroundSubtraction::ZivkovicParams params;
+params.SetFrameSize(width, height);
+params.LowThreshold() = 5.0f*5.0f;
+params.HighThreshold() = 2*params.LowThreshold();	// Note: high threshold is used by post-processing 
+params.Alpha() = 0.001f;
+params.MaxModes() = 3;
+
+Algorithms::BackgroundSubtraction::ZivkovicAGMM bgs;
+bgs.Initalize(params);
+******************************************************************************/
+
+#ifndef ZIVKOVIC_AGMM_H
+#define ZIVKOVIC_AGMM_H
+
+#include "Bgs.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    // --- User adjustable parameters used by the Grimson GMM BGS algorithm ---
+    class ZivkovicParams : public BgsParams
+    {
+    public:
+      float &LowThreshold() { return m_low_threshold; }
+      float &HighThreshold() { return m_high_threshold; }
+
+      float &Alpha() { return m_alpha; }
+      int &MaxModes() { return m_max_modes; }
+
+    private:
+      // Threshold on the squared dist. to decide when a sample is close to an existing 
+      // components. If it is not close to any a new component will be generated. 
+      // Smaller threshold values lead to more generated components and higher threshold values 
+      // lead to a small number of components but they can grow too large.
+      //
+      // It is usual easiest to think of these thresholds as being the number of variances (not standard deviations) 
+      // away from the mean of a pixel before it is considered to be from the foreground.
+      float m_low_threshold;
+      float m_high_threshold;
+
+      // alpha - speed of update - if the time interval you want to average over is T
+      // set alpha=1/T. 
+      float m_alpha;
+
+      // Maximum number of modes (Gaussian components) that will be used per pixel
+      int m_max_modes;
+    };
+
+    // --- Zivkovic AGMM BGS algorithm ---
+    class ZivkovicAGMM : public Bgs
+    {
+    private:
+      struct GMM
+      {
+        float sigma;
+        float muR;
+        float muG;
+        float muB;
+        float weight;
+      };
+
+    public:
+      ZivkovicAGMM();
+      ~ZivkovicAGMM();
+
+      void Initalize(const BgsParams& param);
+
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data,  
+        BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data,  const BwImage& update_mask);
+
+      RgbImage* Background() { return &m_background; }
+
+    private:
+      void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char* pModesUsed, 
+        unsigned char& lowThreshold, unsigned char& highThreshold);
+
+      // User adjustable parameters
+      ZivkovicParams m_params;
+
+      // Threshold when the component becomes significant enough to be included into
+      // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
+      // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+      // it is considered foreground
+      float m_bg_threshold; //1-cf from the paper
+
+      // Initial variance for the newly generated components. 
+      // It will will influence the speed of adaptation. A good guess should be made. 
+      // A simple way is to estimate the typical standard deviation from the images.
+      float m_variance;
+
+      // This is related to the number of samples needed to accept that a component
+      // actually exists. 
+      float m_complexity_prior;
+
+      //data
+      int m_num_bands;	//only RGB now ==3
+
+      // dynamic array for the mixture of Gaussians
+      GMM* m_modes;
+
+      RgbImage m_background;
+
+      //number of Gaussian components per pixel
+      unsigned char* m_modes_per_pixel;
+    };
+  };
+};
+
+#endif
+
+
+
+
+
+
diff --git a/package_bgs/jmo/BGS.h b/package_bgs/jmo/BGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..1fc0e444187b0ff059aaab597310c7c137f0799f
--- /dev/null
+++ b/package_bgs/jmo/BGS.h
@@ -0,0 +1,216 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if !defined(_BGS_H_)
+#define _BGS_H_
+
+#include <cv.h>
+
+
+// TODO check these defines are not used (or not redundant with real params)
+#define MAX_LBP_MODE_NUM	5
+
+#define ROBUST_COLOR_OFFSET	6.0f
+
+#define LOW_INITIAL_MODE_WEIGHT	0.01f
+
+#define MODE_UPDATING_LEARN_RATE	0.01f
+#define WEIGHT_UPDATING_LEARN_RATE	0.01f
+
+#define COLOR_MAX_MIN_OFFSET		5
+
+#define BACKGROUND_MODEL_PERCENT	0.6f
+
+#define PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD	0.2f
+
+#define PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE	6
+#define PATTERN_DIST_CONV_GAUSSIAN_SIGMA	2.5f
+
+#define ROBUST_SHADOW_RATE	0.6f
+#define ROBUST_HIGHLIGHT_RATE	1.20f
+
+#define BINARY_PATTERM_ELEM(c1, c2, offset)	\
+  ((float)(c2)-(float)(c1)+offset>0)
+
+/*		
+#define BINARY_PATTERM_ELEM(c1, c2, offset)	\
+( fabsf((float)(c2)-(float)(c1)) <= offset ? 1 : (float)(c2)-(float)(c1) >=0 )
+*/
+
+#ifndef PI
+#define PI 3.141592653589793f
+#endif
+
+/************************************************************************/
+/* some data structures for multi-level LBP (local binary pattern)      */
+/* texture feature for background subtraction                           */
+/************************************************************************/
+typedef struct _LBP
+{
+  float* bg_pattern;			/* the average local binary pattern of background mode */
+  float* bg_intensity;			/* the average color intensity of background mode */
+  float* max_intensity;			/* the maximal color intensity of background mode */
+  float* min_intensity;			/* the minimal color intensity of background mode */
+  float weight;				/* the weight of background mode, i.e. probability that the background mode belongs to background */
+  float max_weight;			/* the maximal weight of background mode */
+  int bg_layer_num;			/* the background layer number of background mode */
+  unsigned long first_time;				/* the first time of background mode appearing */
+  unsigned long last_time;				/* the last time of background model appearing */
+  int freq;				/* the appearing frequency */
+  //long mnrl;				/* maximum negative run-length */
+  unsigned long layer_time;				/* the first time of background mode becoming a background layer */
+}
+LBPStruct;
+
+typedef struct _PixelLBP
+{
+  LBPStruct* LBPs;			/* the background modes */
+  unsigned short* lbp_idxes;		/* the indices of background modes */
+  unsigned int cur_bg_layer_no;
+  unsigned int num;			/* the total number of background modes */
+  unsigned int bg_num;			/* the number of the first background modes for foreground detection */
+  unsigned char* cur_intensity;		/* the color intensity of current pixel */
+  float* cur_pattern;			/* the local binary pattern of current pixel */
+  float matched_mode_first_time;		/* the index of currently matched pixel mode */
+}
+PixelLBPStruct;
+
+/*********************************************************************************/
+/* should replace the above structure using class in the future (not finished)   */
+/*********************************************************************************/
+
+class BG_PIXEL_MODE
+{
+public:
+  float* bg_lbp_pattern;			/* the average local binary pattern of background mode */
+  float* bg_intensity;			/* the average color intensity of background mode */
+  float* max_intensity;			/* the maximal color intensity of background mode */
+  float* min_intensity;			/* the minimal color intensity of background mode */
+  float weight;				/* the weight of background mode, i.e. probability that the background mode belongs to background */
+  float max_weight;			/* the maximal weight of background mode */
+  int bg_layer_num;			/* the background layer number of background mode */
+
+  int lbp_pattern_length;
+  int color_channel;
+
+  BG_PIXEL_MODE(int _lbp_pattern_length, int _color_channel=3) {
+    lbp_pattern_length = _lbp_pattern_length;
+    color_channel = _color_channel;
+
+    bg_lbp_pattern = new float[lbp_pattern_length];
+    bg_intensity = new float[color_channel];
+    max_intensity = new float[color_channel];
+    min_intensity = new float[color_channel];
+  };
+
+  virtual ~BG_PIXEL_MODE() {
+    delete [] bg_lbp_pattern;
+    delete [] bg_intensity;
+    delete [] max_intensity;
+    delete [] min_intensity;
+  };
+};
+
+class BG_PIXEL_PATTERN
+{
+public:
+  BG_PIXEL_MODE** pixel_MODEs;		/* the background modes */
+  unsigned short* lbp_pattern_idxes;	/* the indices of background modes */
+  unsigned int cur_bg_layer_no;
+  unsigned int num;			/* the total number of background modes */
+  unsigned int bg_num;			/* the number of the first background modes for foreground detection */
+  unsigned char* cur_intensity;		/* the color intensity of current pixel */
+  float* cur_lbp_pattern;			/* the local binary pattern of current pixel */
+
+  int lbp_pattern_length;
+  int color_channel;
+  int pixel_mode_num;
+
+  BG_PIXEL_PATTERN(int _pixel_mode_num, int _lbp_pattern_length, int _color_channel=3) {
+    pixel_mode_num = _pixel_mode_num;
+    lbp_pattern_length = _lbp_pattern_length;
+    color_channel = _color_channel;
+
+    pixel_MODEs = new BG_PIXEL_MODE*[pixel_mode_num];
+
+    for ( int i = 0 ; i < pixel_mode_num ; i++ ) {
+      pixel_MODEs[i] = new BG_PIXEL_MODE(_lbp_pattern_length, _color_channel);
+    }
+
+    lbp_pattern_idxes = new unsigned short[pixel_mode_num];
+    cur_intensity = new unsigned char[color_channel];
+    cur_lbp_pattern = new float[lbp_pattern_length];
+  };
+
+  virtual ~BG_PIXEL_PATTERN() {
+    delete [] lbp_pattern_idxes;
+    delete [] cur_intensity;
+    delete [] cur_lbp_pattern;
+
+    for ( int i = 0 ; i < pixel_mode_num ; i++ )
+      delete pixel_MODEs[i];
+    delete [] pixel_MODEs;
+  };
+};
+
+class IMAGE_BG_MODEL
+{
+  int pixel_length;
+
+  BG_PIXEL_PATTERN** pixel_PATTERNs;
+
+  IMAGE_BG_MODEL(int _pixel_length, int _pixel_mode_num, int _lbp_pattern_length, int _color_channel=3) {
+    pixel_length = _pixel_length;
+
+    pixel_PATTERNs = new BG_PIXEL_PATTERN*[pixel_length];
+    for ( int i = 0 ; i < pixel_length ; i++ ) 
+      pixel_PATTERNs[i] = new BG_PIXEL_PATTERN(_pixel_mode_num, _lbp_pattern_length, _color_channel);
+  }
+  virtual ~IMAGE_BG_MODEL() {
+    for ( int i = 0 ; i < pixel_length ; i++ )
+      delete pixel_PATTERNs[i];
+    delete [] pixel_PATTERNs;
+  }
+};
+
+
+#endif // !defined(_BGS_H_)
diff --git a/package_bgs/jmo/BackgroundSubtractionAPI.h b/package_bgs/jmo/BackgroundSubtractionAPI.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d01d692588e338fad43927761b11e4718d276d6
--- /dev/null
+++ b/package_bgs/jmo/BackgroundSubtractionAPI.h
@@ -0,0 +1,158 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+//////////////////////////////////////////////////////////////////////
+//
+// BackgroundSubtractionAPI.h: 
+//   interface for the BackgroundSubtractionAPI class.
+//
+// A background subtraction algorithm takes as input
+// an RGB image and provide as ouput a Binary mask
+// with a value of 0 for points belonging to the 
+// background, and non zero for points belonging
+// to the foreground.
+//
+//
+//
+// To add:
+//  - a function indicating the valid input and ouput
+//    images 
+//     e.g. RGB  image (default) or greylevel image for the input
+//          char image for the output
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#if !defined(_BACKGROUND_SUBTRACTION_API_H_)
+#define _BACKGROUND_SUBTRACTION_API_H_
+
+#include "cv.h"
+
+class CBackgroundSubtractionAPI  
+{
+public:
+  //CBackgroundSubtractionAPI(){};
+  //virtual ~CBackgroundSubtractionAPI(){};
+
+  //-------------------------------------------------------------
+  // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES
+  // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED
+  void   Init(int width,int height);
+
+  //-------------------------------------------------------------
+  // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND 
+  // SUBTRACTION DOES NOT NEED TO BE PERFORMED
+  // 
+  //  mode is useful to specify if the points to remove from 
+  //  processing are in addition to the ones potentially
+  //  removed according to the configuration file,
+  //  or if they are the only ones to be removed 
+  // 
+  // mode=0 : provided points need to be removed
+  //          in addition to those already removed
+  // mode=1 : the provided points are the only one to remove
+  //          from processing
+  // Note:  maskImage(li,co)=0 indicate the points to remove
+  //       from background processing
+  void   SetValidPointMask(IplImage* maskImage, int mode);
+
+  //-------------------------------------------------------------
+  // 
+  //   set the frame rate, to adjust the update parameters
+  //   to the actual frame rate.
+  //   Can be called only once at initialisation,
+  //   but in online cases, can be used to indicate
+  //   the time interval during the last processed frame 
+  //
+  //   frameDuration is in millisecond
+  void   SetFrameRate(float    frameDuration);
+
+  //-------------------------------------------------------------
+  //   PROVIDE A POINTER TO THE INPUT IMAGE
+  //   -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED
+  //
+  //   Here assumes that the input image will contain RGB images.
+  //   The memory of this image is handled by the caller.
+  //
+  //    The return value indicate whether the actual Background 
+  //    Subtraction algorithm handles RGB images (1) or not (0).
+  //   
+  int  SetRGBInputImage(IplImage  *  inputImage);
+
+  //-------------------------------------------------------------
+  //   PROVIDE A POINTER TO THE RESULT IMAGE
+  //   INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED
+  //  
+  //   The return value is 1 if correct image format is provided,
+  //   otherwise the return value is 0.
+  //   e.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);
+  int  SetForegroundMaskImage(IplImage *fg_mask_img);
+
+  //   The return value is 1 if the function is implemented 
+  //   with correct format, otherwise the return value is 0
+  //   e.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_32F, 1);
+  int  SetForegroundProbImage(IplImage *fg_prob_img);
+
+  //-------------------------------------------------------------
+  // This function should be called each time a new image is 
+  // available in the input image.
+  // 
+  // The return value is 1 if everything goes well,
+  // otherwise the return value is 0.  
+  //
+  int   Process();
+
+  //-------------------------------------------------------------
+  // this function should save parameters and information of the model
+  // (e.g. after a training of the model, or in such a way
+  // that the model can be reload to process the next frame
+  // type of save:
+  void   Save(char   *bg_model_fn);
+
+  //-------------------------------------------------------------
+  // this function should load the parameters necessary
+  // for the processing of the background subtraction or 
+  // load background model information
+  void   Load(char  *bg_model_fn);
+};
+
+#endif // !defined(_BACKGROUND_SUBTRACTION_API_H_)
diff --git a/package_bgs/jmo/BlobExtraction.cpp b/package_bgs/jmo/BlobExtraction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..04560b92cf21a43a315825de24cc7451d6d1c559
--- /dev/null
+++ b/package_bgs/jmo/BlobExtraction.cpp
@@ -0,0 +1,1490 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+//***********************************************************//
+//* Blob analysis package  8 August 2003                    *//
+//* Version 1.0                                             *//
+//* Input: IplImage* binary image                           *//
+//* Output: attributes of each connected region             *//
+//* Author: Dave Grossman                                   *//
+//* Modifications: Francesc Pinyol and Ricard Borras		*//
+//* Email: dgrossman@cdr.stanford.edu                       *//
+//* Email: fpinyol@cvc.uab.es rborras@cvc.uab.es            *//
+//* Acknowledgement: the algorithm has been around > 20 yrs *//
+//***********************************************************//
+
+//! Indica si la connectivitat es a 8 (si es desactiva es a 4)
+#define B_CONNECTIVITAT_8
+
+//! si la imatge �s c�clica verticalment (els blobs que toquen
+//! les vores superior i inferior no es consideren externs)
+#define IMATGE_CICLICA_VERTICAL		1
+//! si la imatge �s c�clica horitzontalment (els blobs que toquen
+//! les vores dreta i esquerra no es consideren externs)
+#define IMATGE_CICLICA_HORITZONTAL	0
+
+#define PERIMETRE_DIAGONAL (1.41421356237310 - 2)
+#define SQRT2	1.41421356237310
+// color dels p�xels de la m�scara per ser exteriors
+#define PIXEL_EXTERIOR 0
+
+
+#include "BlobResult.h"
+#include "BlobExtraction.h"
+
+namespace Blob
+{
+
+/**
+- FUNCI�: BlobAnalysis
+- FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal
+- PAR�METRES:
+- inputImage: Imatge d'entrada. Ha de ser d'un sol canal
+- threshold: Nivell de gris per considerar un pixel blanc o negre
+- maskImage: Imatge de m�scara fora de la cual no es calculen els blobs. A m�s,
+els blobs que toquen els pixels de la m�scara a 0, s�n considerats
+externs
+- borderColor: Color del marc de la imatge (0=black or 1=white)
+- findmoments: calcula els moments dels blobs o no
+- RegionData: on es desar� el resultat
+- RESULTAT:
+- retorna true si tot ha anat b�, false si no. Deixa el resultat a blobs.
+- RESTRICCIONS:
+- La imatge d'entrada ha de ser d'un sol canal
+- AUTOR: dgrossman@cdr.stanford.edu
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+- fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptaci� a les OpenCV
+*/
+bool BlobAnalysis(	IplImage* inputImage,
+  uchar threshold,
+  IplImage* maskImage,
+  bool borderColor,
+  bool findmoments,
+  blob_vector &RegionData )	
+{
+  // dimensions of input image taking in account the ROI
+  int Cols, Rows, startCol, startRow;
+
+  if( inputImage->roi )
+  {
+    CvRect imageRoi = cvGetImageROI( inputImage );
+    startCol = imageRoi.x;
+    startRow = imageRoi.y;
+    Cols = imageRoi.width;
+    Rows = imageRoi.height;
+  }
+  else
+  {
+    startCol = 0;
+    startRow = 0; 
+    Cols = inputImage->width;
+    Rows = inputImage->height;
+  }
+
+  int Trans = Cols;				// MAX trans in any row
+  char* pMask = NULL;
+  char* pImage;
+
+  // Convert image array into transition array. In each row
+  // the transition array tells which columns have a color change
+  int iCol,iRow,iTran, Tran;				// Data for a given run
+  bool ThisCell, LastCell;		// Contents (colors (0 or 1)) within this row
+  int TransitionOffset = 0;		// Performance booster to avoid multiplication
+
+  // row 0 and row Rows+1 represent the border
+  int i;
+  int *Transition;				// Transition Matrix
+
+  int nombre_pixels_mascara = 0;
+  //! Imatge amb el perimetre extern de cada pixel
+  IplImage *imatgePerimetreExtern;
+
+  // input images must have only 1-channel and be an image
+  if( !CV_IS_IMAGE( inputImage ) || (inputImage->nChannels != 1) )
+  {
+    return false;
+  }
+  if( maskImage != NULL )
+  {
+    // input image and mask are a valid image?
+    if( !CV_IS_IMAGE( inputImage ) || !CV_IS_IMAGE( maskImage )) 
+      return false;
+
+    // comprova que la m�scara tingui les mateixes dimensions que la imatge
+    if( inputImage->width != maskImage->width || inputImage->height != maskImage->height )
+    {
+      return false;
+    }
+
+    // comprova que la m�scara sigui una imatge d'un sol canal (grayscale)
+    if( maskImage->nChannels != 1 )
+    {
+      return false;
+    }
+
+  }
+
+  // Initialize Transition array
+  Transition=new int[(Rows + 2)*(Cols + 2)];
+  memset(Transition,0,(Rows + 2) * (Cols + 2)*sizeof(int));
+  Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2;
+
+  // Start at the beginning of the image (startCol, startRow)
+  pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep;
+
+  /*
+  Paral�lelitzaci� del c�lcul de la matriu de transicions
+  Fem que cada iteraci� del for el faci un thread o l'altre ( tenim 2 possibles threads )	
+  */
+  if(maskImage == NULL)
+  {
+    imatgePerimetreExtern = NULL;
+
+    //Fill Transition array
+    for(iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
+    {
+      TransitionOffset = iRow*(Cols + 2); //per a que sigui paral�litzable
+      iTran = 0;					// Index into Transition array
+      Tran = 0;					// No transitions at row start
+      LastCell = borderColor;
+
+      for(iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
+      {
+        if(iCol == 0 || iCol == Cols+1) 
+          ThisCell = borderColor;
+        else
+          ThisCell = ((unsigned char) *(pImage)) > threshold;
+
+        if(ThisCell != LastCell)
+        {
+          Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
+          iTran++;						// Prepare new index
+          LastCell = ThisCell;			// With this color
+        }
+
+        Tran++;	// Tran continues
+        pImage++;
+      }
+
+      Transition[TransitionOffset + iTran] = Tran;	// Save completed run
+      if ( (TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2) )
+      {
+        Transition[TransitionOffset + iTran + 1] = -1;
+      }
+      //jump to next row (beginning from (startCol, startRow))
+      pImage = inputImage->imageData - 1 + startCol + (iRow+startRow)*inputImage->widthStep;
+    }
+  }
+  else
+  {
+    //maskImage not NULL: Cal rec�rrer la m�scara tamb� per calcular la matriu de transicions
+
+    char perimeter;
+    char *pPerimetre;
+
+    // creem la imatge que contindr� el perimetre extern de cada pixel
+    imatgePerimetreExtern = cvCreateImage( cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1);
+    cvSetZero( imatgePerimetreExtern );
+
+    pMask = maskImage->imageData - 1;
+
+    //Fill Transition array
+    for(iRow = 1; iRow < Rows + 1; iRow++)		// Choose a row of Bordered image
+    {
+      TransitionOffset = iRow*(Cols + 2);
+      iTran = 0;					// Index into Transition array
+      Tran = 0;					// No transitions at row start
+      LastCell = borderColor;
+
+      pPerimetre = imatgePerimetreExtern->imageData + (iRow - 1) * imatgePerimetreExtern->widthStep;
+      //pMask = maskImage->imageData + (iRow-1) * maskImage->widthStep;
+
+      for(iCol = 0; iCol < Cols + 2; iCol++)	// Scan that row of Bordered image
+      {
+        if(iCol == 0 || iCol == Cols+1 || ((unsigned char) *pMask) == PIXEL_EXTERIOR) 
+          ThisCell = borderColor;
+        else
+          ThisCell = ((unsigned char) *(pImage)) > threshold;
+
+        if(ThisCell != LastCell)
+        {
+          Transition[TransitionOffset + iTran] = Tran;	// Save completed Tran
+          iTran++;						// Prepare new index
+          LastCell = ThisCell;			// With this color
+        }
+
+        /*////////////////////////////////////////////////////////////////////////
+        Calcul de la imatge amb els pixels externs
+        ////////////////////////////////////////////////////////////////////////*/
+        // pels pixels externs no cal calcular res pq no hi accedir-hem
+        if( (iCol > 0) && (iCol < Cols) )
+        {
+          if( *pMask == PIXEL_EXTERIOR )
+          {
+            *pPerimetre = 0;
+          }
+          else
+          {
+            perimeter = 0;
+
+            // pixels al nord de l'actual
+            if(iRow>1)
+            {
+              if( *(pMask - maskImage->widthStep ) == PIXEL_EXTERIOR) perimeter++;
+            }
+
+            // pixels a l'est i oest de l'actual
+            if( iRow < imatgePerimetreExtern->height )
+            {
+              if( (iCol>0) && (*(pMask-1) == PIXEL_EXTERIOR) ) perimeter++;
+
+              if( ( iCol < imatgePerimetreExtern->width - 1) && (*(pMask+1) == PIXEL_EXTERIOR) ) perimeter++;
+            }
+
+            // pixels al sud de l'actual
+            if( iRow < imatgePerimetreExtern->height - 1)
+            {
+              if( (*(pMask+maskImage->widthStep) == PIXEL_EXTERIOR) ) perimeter++;
+            }
+
+            *pPerimetre = perimeter;
+          }
+        }
+
+        Tran++;	// Tran continues
+        pImage++;
+        pMask++;
+        pPerimetre++;
+      }
+      Transition[TransitionOffset + iTran] = Tran;	// Save completed run
+
+      if ( (TransitionOffset + iTran + 1) < (Rows + 1)*(Cols + 2) )
+      {
+        Transition[TransitionOffset + iTran + 1] = -1;
+      }
+
+
+      //jump to next row (beginning from (startCol, startRow))
+      pImage = inputImage->imageData - 1 + startCol + (iRow+startRow)*inputImage->widthStep;
+      //the mask should be the same size as image Roi, so don't take into account the offset
+      pMask = maskImage->imageData - 1 + iRow*maskImage->widthStep;
+    }
+  }
+
+  // Process transition code depending on Last row and This row
+  //
+  // Last ---++++++--+++++++++++++++-----+++++++++++++++++++-----++++++-------+++---
+  // This -----+++-----++++----+++++++++----+++++++---++------------------++++++++--
+  //
+  // There are various possibilities:
+  //
+  // Case     1       2       3       4       5       6       7       8
+  // Last |xxx    |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx  |ooxxxxx|    xxx|
+  // This |    yyy|    yyy|  yyyy |  yyyyy|yyyyyyy|yyyyyyy|yyyy   |yyyy   |
+  // Here o is optional
+  // 
+  // Here are the primitive tests to distinguish these 6 cases:
+  //   A) Last end < This start - 1 OR NOT		Note: -1
+  //   B) This end < Last start OR NOT
+  //   C) Last start < This start OR NOT
+  //   D) This end < Last end OR NOT
+  //   E) This end = Last end OR NOT
+  //
+  // Here is how to use these tests to determine the case:
+  //   Case 1 = A [=> NOT B AND C AND NOT D AND NOT E]
+  //   Case 2 = C AND NOT D AND NOT E [AND NOT A AND NOT B]
+  //   Case 3 = C AND D [=> NOT E] [AND NOT A AND NOT B]
+  //   Case 4 = C AND NOT D AND E [AND NOT A AND NOT B]
+  //   Case 5 = NOT C AND E [=> NOT D] [AND NOT A AND NOT B]
+  //   Case 6 = NOT C AND NOT D AND NOT E [AND NOT A AND NOT B]
+  //   Case 7 = NOT C AND D [=> NOT E] [AND NOT A AND NOT B]
+  //   Case 8 = B [=> NOT A AND NOT C AND D AND NOT E]
+  //
+  // In cases 2,3,4,5,6,7 the following additional test is needed:
+  //   Match) This color = Last color OR NOT
+  //
+  // In cases 5,6,7 the following additional test is needed:
+  //   Known) This region was already matched OR NOT
+  //
+  // Here are the main tests and actions:
+  //   Case 1: LastIndex++;
+  //   Case 2: if(Match) {y = x;}
+  //           LastIndex++;
+  //   Case 3: if(Match) {y = x;}
+  //           else {y = new}
+  //           ThisIndex++;
+  //   Case 4: if(Match) {y = x;}
+  //           else {y = new}
+  //           LastIndex++;
+  //           ThisIndex++;
+  //   Case 5: if(Match AND NOT Known) {y = x}
+  //           else if(Match AND Known) {Subsume(x,y)}
+  //           LastIndex++;ThisIndex++
+  //   Case 6: if(Match AND NOT Known) {y = x}
+  //           else if(Match AND Known) {Subsume(x,y)}
+  //           LastIndex++;
+  //   Case 7: if(Match AND NOT Known) {y = x}
+  //           else if(Match AND Known) {Subsume(x,y)}
+  //           ThisIndex++;
+  //   Case 8: ThisIndex++;
+
+  int *SubsumedRegion = NULL;			
+
+  double ThisParent;	// These data can change when the line is current
+  double ThisArea;
+  double ThisPerimeter;
+  double ThisSumX = 0;
+  double ThisSumY = 0;
+  double ThisSumXX = 0;
+  double ThisSumYY = 0;
+  double ThisSumXY = 0;
+  double ThisMinX;
+  double ThisMaxX;
+  double ThisMinY;
+  double ThisMaxY;
+  double LastPerimeter;	// This is the only data for retroactive change
+  double ThisExternPerimeter;
+
+  int HighRegionNum = 0;
+  //int RegionNum = 0;
+  int ErrorFlag = 0;
+
+  int LastRow, ThisRow;			// Row number
+  int LastStart, ThisStart;		// Starting column of run
+  int LastEnd, ThisEnd;			// Ending column of run
+  int LastColor, ThisColor;		// Color of run
+
+  int LastIndex, ThisIndex;		// Which run are we up to
+  int LastIndexCount, ThisIndexCount;	// Out of these runs
+  int LastRegionNum, ThisRegionNum;	// Which assignment
+  int *LastRegion;				// Row assignment of region number
+  int *ThisRegion;		// Row assignment of region number
+
+  int LastOffset = -(Trans + 2);	// For performance to avoid multiplication
+  int ThisOffset = 0;				// For performance to avoid multiplication
+  int ComputeData;
+
+  CvPoint actualedge;
+  uchar imagevalue;
+  bool CandidatExterior = false;
+
+  // apuntadors als blobs de la regi� actual i last
+  CBlob *regionDataThisRegion, *regionDataLastRegion;
+
+  LastRegion=new int[Cols+2];
+  ThisRegion=new int[Cols+2];
+
+  for(i = 0; i < Cols + 2; i++)	// Initialize result arrays
+  {
+    LastRegion[i] = -1;
+    ThisRegion[i] = -1;
+  }
+
+  //create the external blob
+  RegionData.push_back( new CBlob() );
+  SubsumedRegion = NewSubsume(SubsumedRegion,0);
+  RegionData[0]->parent = -1;
+  RegionData[0]->area = (double) Transition[0];
+  RegionData[0]->perimeter = (double) (2 + 2 * Transition[0]);
+
+  ThisIndexCount = 1;
+  ThisRegion[0] = 0;	// Border region
+
+  // beginning of the image 
+  // en cada linia, pimage apunta al primer pixel de la fila
+  pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep;
+  //the mask should be the same size as image Roi, so don't take into account the offset
+  if(maskImage!=NULL) pMask = maskImage->imageData - 1;
+
+  char *pImageAux, *pMaskAux = NULL;
+
+  // Loop over all rows
+  for(ThisRow = 1; ThisRow < Rows + 2; ThisRow++)
+  {
+    //cout << "========= THIS ROW = " << ThisRow << endl;	// for debugging
+    ThisOffset += Trans + 2;
+    ThisIndex = 0;
+    LastOffset += Trans + 2;;
+    LastRow = ThisRow - 1;
+    LastIndexCount = ThisIndexCount;
+    LastIndex = 0;
+
+    int EndLast = 0;
+    int EndThis = 0;
+
+    for(int j = 0; j < Trans + 2; j++)
+    {
+      int Index = ThisOffset + j;
+      int TranVal = Transition[Index];
+      if(TranVal > 0) ThisIndexCount = j + 1;	// stop at highest 
+
+      if(ThisRegion[j] == -1)  { EndLast = 1; }
+      if(TranVal < 0) { EndThis = 1; }
+
+      if(EndLast > 0 && EndThis > 0) { break; }
+
+      LastRegion[j] = ThisRegion[j];
+      ThisRegion[j] = -1;		// Flag indicates region is not initialized
+    }
+
+    int MaxIndexCount = LastIndexCount;
+    if(ThisIndexCount > MaxIndexCount) MaxIndexCount = ThisIndexCount;
+
+    // Main loop over runs within Last and This rows
+    while (LastIndex < LastIndexCount && ThisIndex < ThisIndexCount)
+    {
+      ComputeData = 0;
+
+      if(LastIndex == 0) LastStart = 0;
+      else LastStart = Transition[LastOffset + LastIndex - 1];
+      LastEnd = Transition[LastOffset + LastIndex] - 1;
+      LastColor = LastIndex - 2 * (LastIndex / 2);
+      LastRegionNum = LastRegion[LastIndex];
+
+      regionDataLastRegion = RegionData[LastRegionNum];
+
+
+      if(ThisIndex == 0) ThisStart = 0;
+      else ThisStart = Transition[ThisOffset + ThisIndex - 1];
+      ThisEnd = Transition[ThisOffset + ThisIndex] - 1;
+      ThisColor = ThisIndex - 2 * (ThisIndex / 2);
+      ThisRegionNum = ThisRegion[ThisIndex];
+
+      if( ThisRegionNum >= 0 )
+        regionDataThisRegion = RegionData[ThisRegionNum];
+      else
+        regionDataThisRegion = NULL;
+
+
+      // blobs externs
+      CandidatExterior = false;
+      if( 
+#if !IMATGE_CICLICA_VERTICAL
+        ThisRow == 1 || ThisRow == Rows ||
+#endif
+#if !IMATGE_CICLICA_HORITZONTAL
+        ThisStart <= 1 || ThisEnd >= Cols || 
+#endif				
+        GetExternPerimeter( ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern )
+        )
+      {
+        CandidatExterior = true;
+      }
+
+      int TestA = (LastEnd < ThisStart - 1);	// initially false
+      int TestB = (ThisEnd < LastStart);		// initially false
+      int TestC = (LastStart < ThisStart);	// initially false
+      int TestD = (ThisEnd < LastEnd);
+      int TestE = (ThisEnd == LastEnd);
+
+      int TestMatch = (ThisColor == LastColor);		// initially true
+      int TestKnown = (ThisRegion[ThisIndex] >= 0);	// initially false
+
+      int Case = 0;
+      if(TestA) Case = 1;
+      else if(TestB) Case = 8;
+      else if(TestC)
+      {
+        if(TestD) Case = 3;
+        else if(!TestE) Case = 2;
+        else Case = 4;
+      }
+      else
+      {
+        if(TestE) Case = 5;
+        else if(TestD) Case = 7;
+        else Case = 6;
+      }
+
+      // Initialize common variables
+      ThisArea = (float) 0.0;
+
+      if(findmoments)
+      {
+        ThisSumX = ThisSumY = (float) 0.0;
+        ThisSumXX = ThisSumYY = ThisSumXY = (float) 0.0;
+      }
+      ThisMinX = ThisMinY = (float) 1000000.0;
+      ThisMaxX = ThisMaxY = (float) -1.0;
+
+      LastPerimeter = ThisPerimeter = (float) 0.0;
+      ThisParent = (float) -1;
+      ThisExternPerimeter = 0.0;
+
+      // Determine necessary action and take it
+      switch (Case)
+      { 
+      case 1: //|xxx    |
+        //|    yyy|
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        LastIndex++;
+
+        //afegim la cantonada a LastRegion
+        actualedge.x = ThisEnd;
+        actualedge.y = ThisRow - 1;
+        cvSeqPush(regionDataLastRegion->edges,&actualedge);
+
+        //afegim la cantonada a ThisRegion
+        actualedge.x = ThisStart - 1;
+        actualedge.y = ThisRow - 1;
+        cvSeqPush(regionDataThisRegion->edges,&actualedge);
+
+        break;
+
+
+      case 2: //|xxxxoo |
+        //|    yyy|
+
+        if(TestMatch)	// Same color
+        {
+          ThisRegionNum = LastRegionNum;
+          regionDataThisRegion = regionDataLastRegion;
+
+          ThisArea = ThisEnd - ThisStart + 1;
+          LastPerimeter = LastEnd - ThisStart + 1;	// to subtract
+          ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter +
+            PERIMETRE_DIAGONAL*2;
+
+          if( CandidatExterior )
+          {
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+              inputImage->width, inputImage->height, 
+              imatgePerimetreExtern );
+            ThisExternPerimeter += PERIMETRE_DIAGONAL*2;
+          }
+          ComputeData = 1;
+        }
+
+        //afegim la cantonada a ThisRegion
+        if(ThisRegionNum!=-1)
+        {
+          // afegim dos vertexs si s�n diferents, nom�s
+          if(ThisStart - 1 != ThisEnd)
+          {
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          }
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+        }
+        //afegim la cantonada a ThisRegion
+        if(LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+          // afegim dos vertexs si s�n diferents, nom�s
+          if(ThisStart - 1 != ThisEnd)
+          {
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataLastRegion->edges,&actualedge);
+          }
+        }
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        LastIndex++;
+        break;
+
+
+      case 3: //|xxxxxxx|
+        //|  yyyy |
+
+        if(TestMatch)	// Same color
+        {
+          ThisRegionNum = LastRegionNum;
+          regionDataThisRegion = regionDataLastRegion;
+
+          ThisArea = ThisEnd - ThisStart + 1;
+          LastPerimeter = ThisArea;	// to subtract
+          ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL*2;
+          if( CandidatExterior )
+          {
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+              inputImage->width, inputImage->height, 
+              imatgePerimetreExtern );
+
+            ThisExternPerimeter += PERIMETRE_DIAGONAL * 2;
+          }
+        }
+        else		// Different color => New region
+        {
+          ThisParent = LastRegionNum;
+          ThisRegionNum = ++HighRegionNum;
+          ThisArea = ThisEnd - ThisStart + 1;
+          ThisPerimeter = 2 + 2 * ThisArea;
+          RegionData.push_back( new CBlob() );
+          regionDataThisRegion = RegionData.back();
+
+          SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
+          if( CandidatExterior )
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+            inputImage->width, inputImage->height, 
+            imatgePerimetreExtern );
+
+        }
+
+        if(ThisRegionNum!=-1)
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisStart - 1;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          //afegim la cantonada a la regio
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+        }
+        // si hem creat un nou blob, afegim tb a l'anterior
+        if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisStart - 1;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+          //afegim la cantonada a la regio
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+        }
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        ComputeData = 1;
+        ThisIndex++;
+        break;
+
+
+      case 4:	//|xxxxxxx|
+        //|  yyyyy|
+
+        if(TestMatch)	// Same color
+        {
+          ThisRegionNum = LastRegionNum;
+          regionDataThisRegion = regionDataLastRegion;
+          ThisArea = ThisEnd - ThisStart + 1;
+          LastPerimeter = ThisArea;	// to subtract
+          ThisPerimeter = 2 + ThisArea + PERIMETRE_DIAGONAL;
+          if( CandidatExterior )
+          {
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+              inputImage->width, inputImage->height, 
+              imatgePerimetreExtern );
+
+            ThisExternPerimeter += PERIMETRE_DIAGONAL;
+          }
+        }
+        else		// Different color => New region
+        {
+          ThisParent = LastRegionNum;
+          ThisRegionNum = ++HighRegionNum;
+          ThisArea = ThisEnd - ThisStart + 1;
+          ThisPerimeter = 2 + 2 * ThisArea;
+          RegionData.push_back( new CBlob() );
+          regionDataThisRegion = RegionData.back();
+          SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
+          if( CandidatExterior )
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+            inputImage->width, inputImage->height, 
+            imatgePerimetreExtern );
+
+        }
+
+        if(ThisRegionNum!=-1)
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisStart - 1;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+        }
+        // si hem creat un nou blob, afegim tb a l'anterior
+        if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+          actualedge.x = ThisStart - 1;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+        }
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        ComputeData = 1;
+
+#ifdef B_CONNECTIVITAT_8
+        if( TestMatch )
+        {
+          LastIndex++;
+          ThisIndex++;
+        }
+        else
+        {
+          LastIndex++;	
+        }
+#else
+        LastIndex++;
+        ThisIndex++;
+#endif					
+        break;
+
+
+      case 5:	//|ooxxxxx|
+        //|yyyyyyy|
+
+        if(!TestMatch && !TestKnown)	// Different color and unknown => new region
+        {
+          ThisParent = LastRegionNum;
+          ThisRegionNum = ++HighRegionNum;
+          ThisArea = ThisEnd - ThisStart + 1;
+          ThisPerimeter = 2 + 2 * ThisArea;
+          RegionData.push_back( new CBlob() );
+          regionDataThisRegion = RegionData.back();
+          SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
+          if( CandidatExterior )
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+            inputImage->width, inputImage->height, 
+            imatgePerimetreExtern );
+
+        }
+        else if(TestMatch && !TestKnown)	// Same color and unknown
+        {
+          ThisRegionNum = LastRegionNum;
+          regionDataThisRegion = regionDataLastRegion;
+          ThisArea = ThisEnd - ThisStart + 1;
+          LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+          ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter 
+            + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
+          if( CandidatExterior )
+          {
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+              inputImage->width, inputImage->height, 
+              imatgePerimetreExtern );
+
+
+            ThisExternPerimeter += PERIMETRE_DIAGONAL * (LastStart != ThisStart);
+          }
+          ComputeData = 1;
+        }
+        else if(TestMatch && TestKnown)	// Same color and known
+        {
+          LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+          //ThisPerimeter = - LastPerimeter;
+          ThisPerimeter = - 2 * LastPerimeter 
+            + PERIMETRE_DIAGONAL * (LastStart != ThisStart);
+
+          if(ThisRegionNum > LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
+              findmoments, ThisRegionNum, LastRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+              if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+            }					
+            ThisRegionNum = LastRegionNum;
+          }
+          else if(ThisRegionNum < LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
+              findmoments, LastRegionNum, ThisRegionNum );
+
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+              if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+            }					
+            LastRegionNum = ThisRegionNum;
+          }
+        }
+
+
+        if(ThisRegionNum!=-1)
+        {
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+
+          if( ThisStart - 1 != LastEnd )
+          {
+            //afegim la cantonada a la regio
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          }
+        }
+        // si hem creat un nou blob, afegim tb a l'anterior
+        if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+        }
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+
+#ifdef B_CONNECTIVITAT_8
+        if( TestMatch )
+        {
+          LastIndex++;
+          ThisIndex++;
+        }
+        else
+        {
+          LastIndex++;	
+        }
+#else
+        LastIndex++;
+        ThisIndex++;
+#endif	
+        break;
+
+
+      case 6:	//|ooxxx  |
+        //|yyyyyyy|
+
+        if(TestMatch && !TestKnown)
+        {
+          ThisRegionNum = LastRegionNum;
+          regionDataThisRegion = regionDataLastRegion;
+          ThisArea = ThisEnd - ThisStart + 1;
+          LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+          ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
+            + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
+          if( CandidatExterior )
+          {
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+              inputImage->width, inputImage->height, 
+              imatgePerimetreExtern );
+
+
+            ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
+          }
+          ComputeData = 1;
+        }
+        else if(TestMatch && TestKnown)
+        {
+          LastPerimeter = LastEnd - LastStart + 1;	// to subtract
+          //ThisPerimeter = - LastPerimeter;
+          ThisPerimeter = - 2 * LastPerimeter
+            + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
+
+          if(ThisRegionNum > LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
+              findmoments, ThisRegionNum, LastRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+              if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+            }					
+            ThisRegionNum = LastRegionNum;
+          }
+          else if(ThisRegionNum < LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
+              findmoments, LastRegionNum, ThisRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+              if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+            }					
+            LastRegionNum = ThisRegionNum;
+          }
+        }
+
+
+        if(ThisRegionNum!=-1)
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          if( ThisStart - 1 != LastEnd )
+          {
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          }
+        }
+        // si hem creat un nou blob, afegim tb a l'anterior
+        if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+          //afegim la cantonada a la regio
+          if( ThisStart - 1 != LastEnd )
+          {
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          }
+        }					
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        LastIndex++;
+        break;
+
+
+      case 7:	//|ooxxxxx|
+        //|yyyy   |
+
+        if(!TestMatch && !TestKnown)	// Different color and unknown => new region
+        {
+          ThisParent = LastRegionNum;
+          ThisRegionNum = ++HighRegionNum;
+          ThisArea = ThisEnd - ThisStart + 1;
+          ThisPerimeter = 2 + 2 * ThisArea;
+          RegionData.push_back( new CBlob() );
+          regionDataThisRegion = RegionData.back();
+          SubsumedRegion = NewSubsume(SubsumedRegion,HighRegionNum);
+          if( CandidatExterior )
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+            inputImage->width, inputImage->height, 
+            imatgePerimetreExtern );
+
+        }
+        else if(TestMatch && !TestKnown)
+        {
+          ThisRegionNum = LastRegionNum;
+          regionDataThisRegion = regionDataLastRegion;
+          ThisArea = ThisEnd - ThisStart + 1;
+          ThisPerimeter = 2 + ThisArea;
+          LastPerimeter = ThisEnd - LastStart + 1;
+          ThisPerimeter = 2 + 2 * ThisArea - LastPerimeter
+            + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
+          if( CandidatExterior )
+          {
+            ThisExternPerimeter = GetExternPerimeter( ThisStart, ThisEnd, ThisRow, 
+              inputImage->width, inputImage->height, 
+              imatgePerimetreExtern );
+
+            ThisExternPerimeter += PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
+          }
+          ComputeData = 1;
+        }
+        else if(TestMatch && TestKnown)
+        {
+          LastPerimeter = ThisEnd - LastStart + 1;	// to subtract
+          //ThisPerimeter = - LastPerimeter;
+          ThisPerimeter = - 2 * LastPerimeter
+            + PERIMETRE_DIAGONAL + PERIMETRE_DIAGONAL * (ThisStart!=LastStart);
+
+          if(ThisRegionNum > LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
+              findmoments, ThisRegionNum, LastRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+              if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+            }					
+            ThisRegionNum = LastRegionNum;
+          }
+          else if(ThisRegionNum < LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
+              findmoments, LastRegionNum, ThisRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+              if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+            }					
+            LastRegionNum = ThisRegionNum;
+          }
+        }
+
+        if(ThisRegionNum!=-1)
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          if( ThisStart - 1 != LastEnd )
+          {
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          }
+        }
+        // si hem creat un nou blob, afegim tb a l'anterior
+        if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisEnd;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+          if( ThisStart - 1 != LastEnd )
+          {
+            actualedge.x = ThisStart - 1;
+            actualedge.y = ThisRow - 1;
+            cvSeqPush(regionDataThisRegion->edges,&actualedge);
+          }
+        }
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        ThisIndex++;
+        break;
+
+      case 8:	//|    xxx|
+        //|yyyy   |
+
+#ifdef B_CONNECTIVITAT_8					
+        // fusionem blobs
+        if( TestMatch )
+        {
+          if(ThisRegionNum > LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataThisRegion, regionDataLastRegion, 
+              findmoments, ThisRegionNum, LastRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == ThisRegionNum) ThisRegion[iOld] = LastRegionNum;
+              if(LastRegion[iOld] == ThisRegionNum) LastRegion[iOld] = LastRegionNum;
+            }					
+            ThisRegionNum = LastRegionNum;
+          }
+          else if(ThisRegionNum < LastRegionNum)
+          {
+            Subsume(RegionData, HighRegionNum, SubsumedRegion, regionDataLastRegion, regionDataThisRegion, 
+              findmoments, LastRegionNum, ThisRegionNum );
+            for(int iOld = 0; iOld < MaxIndexCount; iOld++)
+            {
+              if(ThisRegion[iOld] == LastRegionNum) ThisRegion[iOld] = ThisRegionNum;
+              if(LastRegion[iOld] == LastRegionNum) LastRegion[iOld] = ThisRegionNum;
+            }					
+            LastRegionNum = ThisRegionNum;
+          }
+
+          regionDataThisRegion->perimeter = regionDataThisRegion->perimeter + PERIMETRE_DIAGONAL*2;
+        }
+#endif
+
+        if(ThisRegionNum!=-1)
+        {
+          //afegim la cantonada a la regio
+          actualedge.x = ThisStart - 1;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataThisRegion->edges,&actualedge);
+        }
+#ifdef B_CONNECTIVITAT_8					
+        // si hem creat un nou blob, afegim tb a l'anterior
+        if(!TestMatch && LastRegionNum!=-1 && LastRegionNum != ThisRegionNum )
+        {
+#endif					
+          //afegim la cantonada a la regio
+          actualedge.x = ThisStart - 1;
+          actualedge.y = ThisRow - 1;
+          cvSeqPush(regionDataLastRegion->edges,&actualedge);
+#ifdef B_CONNECTIVITAT_8
+        }
+#endif
+
+        ThisRegion[ThisIndex] = ThisRegionNum;
+        LastRegion[LastIndex] = LastRegionNum;
+        ThisIndex++;
+#ifdef B_CONNECTIVITAT_8					
+        LastIndex--;
+#endif
+        break;
+
+      default:
+        ErrorFlag = -1;
+      }	// end switch case
+
+      // calculate the blob moments and mean gray level of the current blob (ThisRegionNum)
+      if(ComputeData > 0)
+      {
+        // compute blob moments if necessary
+        if(findmoments)
+        {
+          float ImageRow = (float) (ThisRow - 1);
+
+          for(int k = ThisStart; k <= ThisEnd; k++)
+          {
+            ThisSumX += (float) (k - 1);
+            ThisSumXX += (float) (k - 1) * (k - 1);
+          }
+
+          ThisSumXY = ThisSumX * ImageRow;
+          ThisSumY = ThisArea * ImageRow;
+          ThisSumYY = ThisSumY * ImageRow;
+
+        }
+
+        // compute the mean gray level and its std deviation 
+        if(ThisRow <= Rows )
+        {
+          pImageAux = pImage + ThisStart;
+          if(maskImage!=NULL) pMaskAux = pMask + ThisStart;
+          for(int k = ThisStart; k <= ThisEnd; k++)
+          {
+            if((k>0) && (k <= Cols))
+            {
+              if( maskImage!= NULL)
+              {
+                // nom�s es t� en compte el valor del p�xel de la
+                // imatge que queda dins de la m�scara
+                // (de pas, comptem el nombre de p�xels de la m�scara)
+                if( ((unsigned char) *pMaskAux) != PIXEL_EXTERIOR )
+                {
+                  imagevalue = (unsigned char) (*pImageAux);
+                  regionDataThisRegion->mean+=imagevalue;
+                  regionDataThisRegion->stddev+=imagevalue*imagevalue;
+                }
+                else
+                {
+                  nombre_pixels_mascara++;
+                }
+              }
+              else
+              {
+                imagevalue = (unsigned char) (*pImageAux);
+                regionDataThisRegion->mean+=imagevalue;
+                regionDataThisRegion->stddev+=imagevalue*imagevalue;
+
+              }
+            }
+            pImageAux++;
+            if(maskImage!=NULL) pMaskAux++;
+          }
+        }
+
+        // compute the min and max values of X and Y
+        if(ThisStart - 1 < (int) ThisMinX) ThisMinX = (float) (ThisStart - 1);
+        if(ThisMinX < (float) 0.0) ThisMinX = (float) 0.0;
+        if(ThisEnd > (int) ThisMaxX) ThisMaxX = (float) ThisEnd;
+
+        if(ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1;
+        if(ThisMinY < (float) 0.0) ThisMinY = (float) 0.0;
+        if(ThisRow > ThisMaxY) ThisMaxY = ThisRow;
+      }
+
+      // put the current results into RegionData
+      if(ThisRegionNum >= 0)
+      {
+        if(ThisParent >= 0) { regionDataThisRegion->parent = (int) ThisParent; }
+        regionDataThisRegion->etiqueta = ThisRegionNum;
+        regionDataThisRegion->area += ThisArea;
+        regionDataThisRegion->perimeter += ThisPerimeter;
+        regionDataThisRegion->externPerimeter += ThisExternPerimeter;
+
+        if(ComputeData > 0)
+        {
+          if(findmoments)
+          {
+            regionDataThisRegion->sumx += ThisSumX;
+            regionDataThisRegion->sumy += ThisSumY;
+            regionDataThisRegion->sumxx += ThisSumXX;
+            regionDataThisRegion->sumyy += ThisSumYY;
+            regionDataThisRegion->sumxy += ThisSumXY;
+          }
+          regionDataThisRegion->perimeter -= LastPerimeter;
+          regionDataThisRegion->minx=MIN(regionDataThisRegion->minx,ThisMinX);
+          regionDataThisRegion->maxx=MAX(regionDataThisRegion->maxx,ThisMaxX);
+          regionDataThisRegion->miny=MIN(regionDataThisRegion->miny,ThisMinY);
+          regionDataThisRegion->maxy=MAX(regionDataThisRegion->maxy,ThisMaxY);
+        }
+        // blobs externs
+        if( CandidatExterior )
+        {
+          regionDataThisRegion->exterior = true;
+        }
+
+      }
+    }	// end Main loop
+
+    if(ErrorFlag != 0) return false;
+    // ens situem al primer pixel de la seguent fila
+    pImage = inputImage->imageData - 1 + startCol + (ThisRow+startRow) * inputImage->widthStep;
+
+    if(maskImage!=NULL)
+      pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep;
+  }	// end Loop over all rows
+
+  // eliminem l'�rea del marc
+  // i tamb� els p�xels de la m�scara
+  // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del
+  // blob 0 nom�s ser� cert si la m�scara t� contacte amb el marc.
+  // Si no, s'haur� de trobar quin �s el blob que cont� m�s p�xels del
+  // compte.
+  RegionData[0]->area -= ( Rows + 1 + Cols + 1 )*2 + nombre_pixels_mascara;
+
+  // eliminem el per�metre de m�s:
+  // - sense marc: 2m+2n (per�metre extern)
+  // - amb marc:   2(m+2)+2(n+2) = 2m+2n + 8
+  // (segurament no �s del tot acurat)
+  // (i amb les m�scares encara menys...)
+  RegionData[0]->perimeter -= 8.0;
+
+  // Condense the list
+  blob_vector::iterator itNew, itOld, iti;
+  CBlob *blobActual;
+
+  itNew = RegionData.begin();
+  itOld = RegionData.begin();
+  int iNew = 0;
+  for(int iOld = 0; iOld <= HighRegionNum; iOld++, itOld++)
+  {
+    if(SubsumedRegion[iOld] < 1)	// This number not subsumed
+    {
+      // Move data from old region number to new region number
+      //*RegionData[iNew] = *RegionData[iOld];
+      **itNew = **itOld;
+
+      // Update and parent pointer if necessary
+      iti = RegionData.begin();
+      for(int i = 0; i <= HighRegionNum; i++)
+      {
+        //if(RegionData[i]->parent == iOld) { RegionData[i]->parent = iNew; }
+        if((*iti)->parent == iOld) { (*iti)->parent = iNew; }
+
+        iti++;
+      }
+      iNew++;
+      itNew++;
+    }	
+  }
+
+
+  HighRegionNum = iNew - 1;				// Update where the data ends
+  RegionData[HighRegionNum]->parent = -1;	// and set end of array flag
+
+
+  if(findmoments)
+  {
+    iti = RegionData.begin();
+    // Normalize summation fields into moments 
+    for(ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
+    {
+      blobActual = *iti;
+
+      // Get averages
+      blobActual->sumx /= blobActual->area;
+      blobActual->sumy /= blobActual->area;
+      blobActual->sumxx /= blobActual->area;
+      blobActual->sumyy /= blobActual->area;
+      blobActual->sumxy /= blobActual->area;
+
+      // Create moments
+      blobActual->sumxx -= blobActual->sumx * blobActual->sumx;
+      blobActual->sumyy -= blobActual->sumy * blobActual->sumy;
+      blobActual->sumxy -= blobActual->sumx * blobActual->sumy;
+      if(blobActual->sumxy > -1.0E-14 && blobActual->sumxy < 1.0E-14)
+      {
+        blobActual->sumxy = (float) 0.0; // Eliminate roundoff error
+      }
+
+    }
+  }
+
+  //Get the real mean and std deviation
+  iti = RegionData.begin();
+  for(ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++)
+  {
+    blobActual = *iti;
+    if(blobActual->area > 1)
+    {
+      blobActual->stddev =
+        sqrt(
+        (
+        blobActual->stddev * blobActual->area -
+        blobActual->mean * blobActual->mean 
+        )/
+        (blobActual->area*(blobActual->area-1))
+        );
+    }
+    else
+      blobActual->stddev=0;
+
+    if(blobActual->area > 0)
+      blobActual->mean/=blobActual->area;
+    else
+      blobActual->mean = 0;
+
+  }
+  // eliminem els blobs subsumats
+  blob_vector::iterator itBlobs = RegionData.begin() + HighRegionNum + 1;
+  while( itBlobs != RegionData.end() )
+  {
+    delete *itBlobs;
+    //RegionData.erase( itBlobs );
+    itBlobs++;
+  }
+  RegionData.erase( RegionData.begin() + HighRegionNum + 1, RegionData.end() );
+
+  //free(RegionData);
+  free(SubsumedRegion);
+  delete Transition;
+  delete ThisRegion;
+  delete LastRegion;
+
+  if( imatgePerimetreExtern ) cvReleaseImage(&imatgePerimetreExtern);
+
+  return true;
+}
+
+
+int *NewSubsume(int *subsumed, int index_subsume)
+{
+  if( index_subsume == 0 )
+  {
+    subsumed = (int*)malloc(sizeof(int));
+  }
+  else
+  {
+    subsumed = (int*)realloc(subsumed,(index_subsume+1)*sizeof(int));
+  }
+  subsumed[index_subsume]=0;
+  return subsumed;
+}
+
+/**
+Fusiona dos blobs i afegeix el blob les caracter�stiques del blob RegionData[HiNum]
+al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum]
+*/
+void Subsume(blob_vector &RegionData,
+  int HighRegionNum,
+  int* SubsumedRegion,
+  CBlob* blobHi,
+  CBlob* blobLo,
+  bool findmoments,
+  int HiNum,
+  int LoNum)
+{
+  // cout << "\nSubsuming " << HiNum << " into " << LoNum << endl; // for debugging
+
+  int i;
+
+  blobLo->minx=MIN(blobHi->minx,blobLo->minx);
+  blobLo->miny=MIN(blobHi->miny,blobLo->miny);
+  blobLo->maxx=MAX(blobHi->maxx,blobLo->maxx);
+  blobLo->maxy=MAX(blobHi->maxy,blobLo->maxy);
+  blobLo->area+=blobHi->area;	
+  blobLo->perimeter+=blobHi->perimeter;
+  blobLo->externPerimeter += blobHi->externPerimeter;
+  blobLo->exterior = blobLo->exterior || blobHi->exterior;
+  blobLo->mean += blobHi->mean;
+  blobLo->stddev += blobHi->stddev;	
+
+  if( findmoments )
+  {
+    blobLo->sumx+=blobHi->sumx;	
+    blobLo->sumy+=blobHi->sumy;	
+    blobLo->sumxx+=blobHi->sumxx;	
+    blobLo->sumyy+=blobHi->sumyy;	
+    blobLo->sumxy+=blobHi->sumxy;
+  }
+  // Make sure no region still has subsumed region as parent
+  blob_vector::iterator it = (RegionData.begin() + HiNum + 1);
+
+  for(i = HiNum + 1; i <= HighRegionNum; i++, it++)
+  {
+    if((*it)->parent == (float) HiNum) { (*it)->parent = LoNum; }
+  }
+
+  // Mark dead region number for future compression
+  SubsumedRegion[HiNum] = 1;
+  // marquem el blob com a lliure
+  blobHi->etiqueta=-1;
+
+  // Atenci�!!!! abans d'eliminar els edges 
+  // s'han de traspassar del blob HiNum al blob LoNum
+  blobHi->CopyEdges( *blobLo );
+  blobHi->ClearEdges();
+}
+
+/**
+- FUNCI�: GetExternPerimeter
+- FUNCIONALITAT: Retorna el perimetre extern d'una run lenght
+- PAR�METRES:
+- start: columna d'inici del run
+- end: columna final del run
+- row: fila del run
+- maskImage: m�scara pels pixels externs
+- RESULTAT:
+- quantitat de perimetre extern d'un run, suposant que �s un blob 
+d'una �nica fila d'al�ada
+- RESTRICCIONS:
+- AUTOR: 
+- DATA DE CREACI�: 2006/02/27
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+double GetExternPerimeter( int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern )
+{
+  double perimeter = 0.0f;
+  char *pPerimetre;
+
+
+  // comprovem les dimensions de la imatge
+  perimeter += ( start <= 0 ) + ( end >= width - 1 );
+  if(row <= 1 ) perimeter+= start - end;
+  if(row >= height - 1 ) perimeter+= start - end;
+
+
+  // comprovem els pixels que toquen a la m�scara (si s'escau)
+  if( imatgePerimetreExtern != NULL )
+  {
+    if( row <= 0 || row >= height ) return perimeter;
+
+    if( start < 0 ) start = 1;
+    if( end >= width ) end = width - 2;
+
+    pPerimetre = imatgePerimetreExtern->imageData + (row - 1) * imatgePerimetreExtern->widthStep + start;
+    for (int x = start - 1; x <= end; x++ )
+    {
+      perimeter += *pPerimetre;
+      pPerimetre++;
+    }
+  }
+
+  return perimeter;
+}
+
+}
diff --git a/package_bgs/jmo/BlobExtraction.h b/package_bgs/jmo/BlobExtraction.h
new file mode 100644
index 0000000000000000000000000000000000000000..157ee58a5552594aa5d4ccc6e8e77ac322c7eaf2
--- /dev/null
+++ b/package_bgs/jmo/BlobExtraction.h
@@ -0,0 +1,76 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+//***********************************************************//
+//* Blob analysis package  8 August 2003                    *//
+//* Version 1.0                                             *//
+//* Input: IplImage* binary image                           *//
+//* Output: attributes of each connected region             *//
+//* Author: Dave Grossman                                   *//
+//* Email: dgrossman@cdr.stanford.edu                       *//
+//* Acknowledgement: the algorithm has been around > 20 yrs *//
+//***********************************************************//
+
+
+#if !defined(_CLASSE_BLOBEXTRACTION_INCLUDED)
+#define _CLASSE_BLOBEXTRACTION_INCLUDED
+
+namespace Blob
+{
+
+//! Extreu els blobs d'una imatge
+bool BlobAnalysis(IplImage* inputImage, uchar threshold, IplImage* maskImage,
+  bool borderColor, bool findmoments, blob_vector &RegionData );
+
+
+// FUNCIONS AUXILIARS
+
+//! Fusiona dos blobs
+void Subsume(blob_vector &RegionData, int, int*, CBlob*, CBlob*, bool, int, int );
+//! Reallocata el vector auxiliar de blobs subsumats
+int *NewSubsume(int *SubSumedRegion, int elems_inbuffer);
+//! Retorna el perimetre extern d'una run lenght
+double GetExternPerimeter( int start, int end, int row, int width, int height, IplImage *maskImage );
+}
+
+#endif //_CLASSE_BLOBEXTRACTION_INCLUDED
+
diff --git a/package_bgs/jmo/BlobLibraryConfiguration.h b/package_bgs/jmo/BlobLibraryConfiguration.h
new file mode 100644
index 0000000000000000000000000000000000000000..48119f7c7c679a3a7d89a16104a2779e4296ed33
--- /dev/null
+++ b/package_bgs/jmo/BlobLibraryConfiguration.h
@@ -0,0 +1,62 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/************************************************************************
+BlobLibraryConfiguration.h
+
+FUNCIONALITAT: Configuraci� del comportament global de la llibreria
+AUTOR: Inspecta S.L.
+MODIFICACIONS (Modificaci�, Autor, Data):
+
+FUNCTIONALITY: Global configuration of the library
+AUTHOR: Inspecta S.L.
+MODIFICATIONS (Modification, Author, Date):
+
+**************************************************************************/
+
+//! Indica si es volen fer servir les MatrixCV o no
+//! Use/Not use the MatrixCV class
+//#define MATRIXCV_ACTIU
+
+// Uses/not use the blob object factory
+//#define BLOB_OBJECT_FACTORY
+
diff --git a/package_bgs/jmo/BlobResult.cpp b/package_bgs/jmo/BlobResult.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbd312a6db31297e5ca8df233ab17db69fc96e5c
--- /dev/null
+++ b/package_bgs/jmo/BlobResult.cpp
@@ -0,0 +1,920 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/************************************************************************
+BlobResult.cpp
+
+FUNCIONALITAT: Implementaci� de la classe CBlobResult
+AUTOR: Inspecta S.L.
+MODIFICACIONS (Modificaci�, Autor, Data):
+
+**************************************************************************/
+
+#include <limits.h>
+#include <stdio.h>
+#include <functional>
+#include <algorithm>
+#include "BlobResult.h"
+#include "BlobExtraction.h"
+#ifdef _DEBUG
+#include <afx.h>			//suport per a CStrings
+#include <afxwin.h>			//suport per a AfxMessageBox
+#endif
+
+/**************************************************************************
+Constructors / Destructors
+**************************************************************************/
+
+namespace Blob
+{
+
+/**
+- FUNCI�: CBlobResult
+- FUNCIONALITAT: Constructor estandard.
+- PAR�METRES:
+- RESULTAT:
+- Crea un CBlobResult sense cap blob
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobResult
+- FUNCTIONALITY: Standard constructor
+- PARAMETERS:
+- RESULT:
+- creates an empty set of blobs
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlobResult::CBlobResult()
+{
+  m_blobs = blob_vector();
+}
+
+/**
+- FUNCI�: CBlobResult
+- FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seq��ncia de blobs 
+amb els blobs resultants de l'an�lisi de blobs de la imatge.
+- PAR�METRES:
+- source: imatge d'on s'extreuran els blobs
+- mask: m�scara a aplicar. Nom�s es calcularan els blobs on la m�scara sigui 
+diferent de 0. Els blobs que toquin a un pixel 0 de la m�scara seran 
+considerats exteriors.
+- threshold: llindar que s'aplicar� a la imatge source abans de calcular els blobs
+- findmoments: indica si s'han de calcular els moments de cada blob
+- RESULTAT:
+- objecte CBlobResult amb els blobs de la imatge source
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlob
+- FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in
+the image
+- PARAMETERS:
+- source: image to extract the blobs from
+- mask: optional mask to apply. The blobs will be extracted where the mask is
+not 0. All the neighbouring blobs where the mask is 0 will be extern blobs
+- threshold: threshold level to apply to the image before computing blobs
+- findmoments: true to calculate the blob moments (slower)
+- RESULT:
+- object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS
+if some error appears in the BlobAnalysis function
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments)
+{
+  bool success;
+
+  try
+  {
+    // cridem la funci� amb el marc a true=1=blanc (aix� no unir� els blobs externs)
+    success = BlobAnalysis(source,(uchar)threshold,mask,true,findmoments, m_blobs );
+  }
+  catch(...)
+  {
+    success = false;
+  }
+
+  if( !success ) throw EXCEPCIO_CALCUL_BLOBS;
+}
+
+/**
+- FUNCI�: CBlobResult
+- FUNCIONALITAT: Constructor de c�pia. Inicialitza la seq��ncia de blobs 
+amb els blobs del par�metre.
+- PAR�METRES:
+- source: objecte que es copiar�
+- RESULTAT:
+- objecte CBlobResult amb els blobs de l'objecte source
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobResult
+- FUNCTIONALITY: Copy constructor
+- PARAMETERS:
+- source: object to copy
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlobResult::CBlobResult( const CBlobResult &source )
+{
+  m_blobs = blob_vector( source.GetNumBlobs() );
+
+  // creem el nou a partir del passat com a par�metre
+  m_blobs = blob_vector( source.GetNumBlobs() );
+  // copiem els blobs de l'origen a l'actual
+  blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
+  blob_vector::iterator pBlobsDst = m_blobs.begin();
+
+  while( pBlobsSrc != source.m_blobs.end() )
+  {
+    // no podem cridar a l'operador = ja que blob_vector �s un 
+    // vector de CBlob*. Per tant, creem un blob nou a partir del
+    // blob original
+    *pBlobsDst = new CBlob(**pBlobsSrc);
+    pBlobsSrc++;
+    pBlobsDst++;
+  }
+}
+
+
+
+/**
+- FUNCI�: ~CBlobResult
+- FUNCIONALITAT: Destructor estandard.
+- PAR�METRES:
+- RESULTAT:
+- Allibera la mem�ria reservada de cadascun dels blobs de la classe
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: ~CBlobResult
+- FUNCTIONALITY: Destructor
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlobResult::~CBlobResult()
+{
+  ClearBlobs();
+}
+
+/**************************************************************************
+Operadors / Operators
+**************************************************************************/
+
+
+/**
+- FUNCI�: operador =
+- FUNCIONALITAT: Assigna un objecte source a l'actual
+- PAR�METRES:
+- source: objecte a assignar
+- RESULTAT:
+- Substitueix els blobs actuals per els de l'objecte source
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: Assigment operator
+- FUNCTIONALITY: 
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlobResult& CBlobResult::operator=(const CBlobResult& source)
+{
+  // si ja s�n el mateix, no cal fer res
+  if (this != &source)
+  {
+    // alliberem el conjunt de blobs antic
+    for( int i = 0; i < GetNumBlobs(); i++ )
+    {
+      delete m_blobs[i];
+    }
+    m_blobs.clear();
+    // creem el nou a partir del passat com a par�metre
+    m_blobs = blob_vector( source.GetNumBlobs() );
+    // copiem els blobs de l'origen a l'actual
+    blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
+    blob_vector::iterator pBlobsDst = m_blobs.begin();
+
+    while( pBlobsSrc != source.m_blobs.end() )
+    {
+      // no podem cridar a l'operador = ja que blob_vector �s un 
+      // vector de CBlob*. Per tant, creem un blob nou a partir del
+      // blob original
+      *pBlobsDst = new CBlob(**pBlobsSrc);
+      pBlobsSrc++;
+      pBlobsDst++;
+    }
+  }
+  return *this;
+}
+
+
+/**
+- FUNCI�: operador +
+- FUNCIONALITAT: Concatena els blobs de dos CBlobResult
+- PAR�METRES:
+- source: d'on s'agafaran els blobs afegits a l'actual
+- RESULTAT:
+- retorna un nou CBlobResult amb els dos CBlobResult concatenats
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- NOTA: per la implementaci�, els blobs del par�metre es posen en ordre invers
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: + operator
+- FUNCTIONALITY: Joins the blobs in source with the current ones
+- PARAMETERS:
+- source: object to copy the blobs
+- RESULT:
+- object with the actual blobs and the source blobs
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlobResult CBlobResult::operator+( const CBlobResult& source )
+{	
+  //creem el resultat a partir dels blobs actuals
+  CBlobResult resultat( *this );
+
+  // reservem mem�ria per als nous blobs
+  resultat.m_blobs.resize( resultat.GetNumBlobs() + source.GetNumBlobs() );
+
+  // declarem els iterador per rec�rrer els blobs d'origen i desti
+  blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin();
+  blob_vector::iterator pBlobsDst = resultat.m_blobs.end();
+
+  // insertem els blobs de l'origen a l'actual
+  while( pBlobsSrc != source.m_blobs.end() )
+  {
+    pBlobsDst--;
+    *pBlobsDst = new CBlob(**pBlobsSrc);
+    pBlobsSrc++;
+  }
+
+  return resultat;
+}
+
+/**************************************************************************
+Operacions / Operations
+**************************************************************************/
+
+/**
+- FUNCI�: AddBlob
+- FUNCIONALITAT: Afegeix un blob al conjunt
+- PAR�METRES:
+- blob: blob a afegir
+- RESULTAT:
+- modifica el conjunt de blobs actual
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 2006/03/01
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+void CBlobResult::AddBlob( CBlob *blob )
+{
+  if( blob != NULL )
+    m_blobs.push_back( new CBlob( blob ) );
+}
+
+
+#ifdef MATRIXCV_ACTIU
+
+/**
+- FUNCI�: GetResult
+- FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe
+- PAR�METRES:
+- evaluador: Qualsevol objecte derivat de COperadorBlob
+- RESULTAT:
+- Retorna un array de double's amb el resultat per cada blob
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: GetResult
+- FUNCTIONALITY: Computes the function evaluador on all the blobs of the class
+and returns a vector with the result
+- PARAMETERS:
+- evaluador: function to apply to each blob (any object derived from the 
+COperadorBlob class )
+- RESULT:
+- vector with all the results in the same order as the blobs
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double_vector CBlobResult::GetResult( funcio_calculBlob *evaluador ) const
+{
+  if( GetNumBlobs() <= 0 )
+  {
+    return double_vector();
+  }
+
+  // definim el resultat
+  double_vector result = double_vector( GetNumBlobs() );
+  // i iteradors sobre els blobs i el resultat
+  double_vector::iterator itResult = result.GetIterator();
+  blob_vector::const_iterator itBlobs = m_blobs.begin();
+
+  // avaluem la funci� en tots els blobs
+  while( itBlobs != m_blobs.end() )
+  {
+    *itResult = (*evaluador)(**itBlobs);
+    itBlobs++;
+    itResult++;
+  }
+  return result;
+}
+#endif
+
+/**
+- FUNCI�: GetSTLResult
+- FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe
+- PAR�METRES:
+- evaluador: Qualsevol objecte derivat de COperadorBlob
+- RESULTAT:
+- Retorna un array de double's STL amb el resultat per cada blob
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: GetResult
+- FUNCTIONALITY: Computes the function evaluador on all the blobs of the class
+and returns a vector with the result
+- PARAMETERS:
+- evaluador: function to apply to each blob (any object derived from the 
+COperadorBlob class )
+- RESULT:
+- vector with all the results in the same order as the blobs
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double_stl_vector CBlobResult::GetSTLResult( funcio_calculBlob *evaluador ) const
+{
+  if( GetNumBlobs() <= 0 )
+  {
+    return double_stl_vector();
+  }
+
+  // definim el resultat
+  double_stl_vector result = double_stl_vector( GetNumBlobs() );
+  // i iteradors sobre els blobs i el resultat
+  double_stl_vector::iterator itResult = result.begin();
+  blob_vector::const_iterator itBlobs = m_blobs.begin();
+
+  // avaluem la funci� en tots els blobs
+  while( itBlobs != m_blobs.end() )
+  {
+    *itResult = (*evaluador)(**itBlobs);
+    itBlobs++;
+    itResult++;
+  }
+  return result;
+}
+
+/**
+- FUNCI�: GetNumber
+- FUNCIONALITAT: Calcula el resultat especificat sobre un �nic blob de la classe
+- PAR�METRES:
+- evaluador: Qualsevol objecte derivat de COperadorBlob
+- indexblob: n�mero de blob del que volem calcular el resultat.
+- RESULTAT:
+- Retorna un double amb el resultat
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: GetNumber
+- FUNCTIONALITY: Computes the function evaluador on a blob of the class
+- PARAMETERS:
+- indexBlob: index of the blob to compute the function
+- evaluador: function to apply to each blob (any object derived from the 
+COperadorBlob class )
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobResult::GetNumber( int indexBlob, funcio_calculBlob *evaluador ) const
+{
+  if( indexBlob < 0 || indexBlob >= GetNumBlobs() )
+    RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS );
+  return (*evaluador)( *m_blobs[indexBlob] );
+}
+
+/////////////////////////// FILTRAT DE BLOBS ////////////////////////////////////
+
+/**
+- FUNCI�: Filter
+- FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb nom�s 
+els blobs que han passat el filtre.
+El filtrat es basa en especificar condicions sobre un resultat dels blobs
+i seleccionar (o excloure) aquells blobs que no compleixen una determinada
+condicio
+- PAR�METRES:
+- dst: variable per deixar els blobs filtrats
+- filterAction:	acci� de filtrat. Incloure els blobs trobats (B_INCLUDE),
+o excloure els blobs trobats (B_EXCLUDE)
+- evaluador: Funci� per evaluar els blobs (qualsevol objecte derivat de COperadorBlob
+- Condition: tipus de condici� que ha de superar la mesura (FilterType) 
+sobre cada blob per a ser considerat.
+B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL,
+B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE
+- LowLimit:  valor num�ric per a la comparaci� (Condition) de la mesura (FilterType)
+- HighLimit: valor num�ric per a la comparaci� (Condition) de la mesura (FilterType)
+(nom�s t� sentit per a aquelles condicions que tenen dos valors 
+(B_INSIDE, per exemple).
+- RESULTAT:
+- Deixa els blobs resultants del filtrat a destination
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: Filter
+- FUNCTIONALITY: Get some blobs from the class based on conditions on measures
+of the blobs. 
+- PARAMETERS:
+- dst: where to store the selected blobs
+- filterAction:	B_INCLUDE: include the blobs which pass the filter in the result 
+B_EXCLUDE: exclude the blobs which pass the filter in the result 
+- evaluador: Object to evaluate the blob
+- Condition: How to decide if  the result returned by evaluador on each blob
+is included or not. It can be:
+B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL,
+B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE
+- LowLimit:  numerical value to evaluate the Condition on evaluador(blob)
+- HighLimit: numerical value to evaluate the Condition on evaluador(blob).
+Only useful for B_INSIDE and B_OUTSIDE
+- RESULT:
+- It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE)
+the Condition on the result returned by evaluador on each blob
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlobResult::Filter(CBlobResult &dst, 
+  int filterAction, 
+  funcio_calculBlob *evaluador, 
+  int condition, 
+  double lowLimit, double highLimit /*=0*/)
+
+{
+  int i, numBlobs;
+  bool resultavaluacio;
+  double_stl_vector avaluacioBlobs;
+  double_stl_vector::iterator itavaluacioBlobs;
+
+  if( GetNumBlobs() <= 0 ) return;
+  if( !evaluador ) return;
+  //avaluem els blobs amb la funci� pertinent	
+  avaluacioBlobs = GetSTLResult(evaluador);
+  itavaluacioBlobs = avaluacioBlobs.begin();
+  numBlobs = GetNumBlobs();
+  switch(condition)
+  {
+  case B_EQUAL:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio= *itavaluacioBlobs == lowLimit;
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }				
+    }
+    break;
+  case B_NOT_EQUAL:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio = *itavaluacioBlobs != lowLimit;
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  case B_GREATER:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio= *itavaluacioBlobs > lowLimit;
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  case B_LESS:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio= *itavaluacioBlobs < lowLimit;
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  case B_GREATER_OR_EQUAL:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio= *itavaluacioBlobs>= lowLimit;
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  case B_LESS_OR_EQUAL:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio= *itavaluacioBlobs <= lowLimit;
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  case B_INSIDE:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio=( *itavaluacioBlobs >= lowLimit) && ( *itavaluacioBlobs <= highLimit); 
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  case B_OUTSIDE:
+    for(i=0;i<numBlobs;i++, itavaluacioBlobs++)
+    {
+      resultavaluacio=( *itavaluacioBlobs < lowLimit) || ( *itavaluacioBlobs > highLimit); 
+      if( ( resultavaluacio && filterAction == B_INCLUDE ) ||
+        ( !resultavaluacio && filterAction == B_EXCLUDE ))
+      {
+        dst.m_blobs.push_back( new CBlob( GetBlob( i ) ));
+      }
+    }
+    break;
+  }
+
+
+  // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult
+  // ( operacio inline )
+  if( &dst == this ) 
+  {
+    // esborrem els primers blobs ( que s�n els originals )
+    // ja que els tindrem replicats al final si passen el filtre
+    blob_vector::iterator itBlobs = m_blobs.begin();
+    for( int i = 0; i < numBlobs; i++ )
+    {
+      delete *itBlobs;
+      itBlobs++;
+    }
+    m_blobs.erase( m_blobs.begin(), itBlobs );
+  }
+}
+
+
+/**
+- FUNCI�: GetBlob
+- FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1)
+- PAR�METRES:
+- indexblob: index del blob a retornar
+- RESULTAT:
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/*
+- FUNCTION: GetBlob
+- FUNCTIONALITY: Gets the n-th blob (without ordering the blobs)
+- PARAMETERS:
+- indexblob: index in the blob array
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlob CBlobResult::GetBlob(int indexblob) const
+{	
+  if( indexblob < 0 || indexblob >= GetNumBlobs() )
+    RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS );
+
+  return *m_blobs[indexblob];
+}
+CBlob *CBlobResult::GetBlob(int indexblob)
+{	
+  if( indexblob < 0 || indexblob >= GetNumBlobs() )
+    RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS );
+
+  return m_blobs[indexblob];
+}
+
+/**
+- FUNCI�: GetNthBlob
+- FUNCIONALITAT: Retorna l'en�ssim blob segons un determinat criteri
+- PAR�METRES:
+- criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob)
+- nBlob: index del blob a retornar
+- dst: on es retorna el resultat
+- RESULTAT:
+- retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri
+en ordre DESCENDENT. Per exemple, per obtenir el blob major:
+GetNthBlob( CBlobGetArea(), 0, blobMajor );
+GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob m�s gran)
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/*
+- FUNCTION: GetNthBlob
+- FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria
+- PARAMETERS:
+- criteri: criteria to order the blob array
+- nBlob: index of the returned blob in the ordered blob array
+- dst: where to store the result
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlobResult::GetNthBlob( funcio_calculBlob *criteri, int nBlob, CBlob &dst ) const
+{
+  // verifiquem que no estem accedint fora el vector de blobs
+  if( nBlob < 0 || nBlob >= GetNumBlobs() )
+  {
+    //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS );
+    dst = CBlob();
+    return;
+  }
+
+  double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat;
+  double valorEnessim;
+
+  //avaluem els blobs amb la funci� pertinent	
+  avaluacioBlobs = GetSTLResult(criteri);
+
+  avaluacioBlobsOrdenat = double_stl_vector( GetNumBlobs() );
+
+  // obtenim els nBlob primers resultats (en ordre descendent)
+  std::partial_sort_copy( avaluacioBlobs.begin(), 
+    avaluacioBlobs.end(),
+    avaluacioBlobsOrdenat.begin(), 
+    avaluacioBlobsOrdenat.end(),
+    std::greater<double>() );
+
+  valorEnessim = avaluacioBlobsOrdenat[nBlob];
+
+  // busquem el primer blob que t� el valor n-ssim
+  double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin();
+
+  bool trobatBlob = false;
+  int indexBlob = 0;
+  while( itAvaluacio != avaluacioBlobs.end() && !trobatBlob )
+  {
+    if( *itAvaluacio == valorEnessim )
+    {
+      trobatBlob = true;
+      dst = CBlob( GetBlob(indexBlob));
+    }
+    itAvaluacio++;
+    indexBlob++;
+  }
+}
+
+/**
+- FUNCI�: ClearBlobs
+- FUNCIONALITAT: Elimina tots els blobs de l'objecte
+- PAR�METRES:
+- RESULTAT: 
+- Allibera tota la mem�ria dels blobs
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s Navarra
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/*
+- FUNCTION: ClearBlobs
+- FUNCTIONALITY: Clears all the blobs from the object and releases all its memory
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlobResult::ClearBlobs()
+{
+  /*for( int i = 0; i < GetNumBlobs(); i++ )
+  {
+  delete m_blobs[i];
+  }*/
+  blob_vector::iterator itBlobs = m_blobs.begin();
+  while( itBlobs != m_blobs.end() )
+  {
+    delete *itBlobs;
+    itBlobs++;
+  }
+
+  m_blobs.clear();
+}
+
+/**
+- FUNCI�: RaiseError
+- FUNCIONALITAT: Funci� per a notificar errors al l'usuari (en debug) i llen�a
+les excepcions
+- PAR�METRES:
+- errorCode: codi d'error
+- RESULTAT: 
+- Ensenya un missatge a l'usuari (en debug) i llen�a una excepci�
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s Navarra
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/*
+- FUNCTION: RaiseError
+- FUNCTIONALITY: Error handling function
+- PARAMETERS:
+- errorCode: reason of the error
+- RESULT:
+- in _DEBUG version, shows a message box with the error. In release is silent.
+In both cases throws an exception with the error.
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlobResult::RaiseError(const int errorCode) const
+{
+  // estem en mode debug?
+#ifdef _DEBUG
+  CString msg, format = "Error en CBlobResult: %s";
+
+  switch (errorCode)
+  {
+  case EXCEPTION_BLOB_OUT_OF_BOUNDS:
+    msg.Format(format, "Intentant accedir a un blob no existent");
+    break;
+  default:
+    msg.Format(format, "Codi d'error desconegut");
+    break;
+  }
+
+  AfxMessageBox(msg);
+
+#endif
+  throw errorCode;
+}
+
+
+
+/**************************************************************************
+Auxiliars / Auxiliary functions
+**************************************************************************/
+
+
+/**
+- FUNCI�: PrintBlobs
+- FUNCIONALITAT: Escriu els par�metres (�rea, per�metre, exterior, mitjana) 
+de tots els blobs a un fitxer.
+- PAR�METRES:
+- nom_fitxer: path complet del fitxer amb el resultat
+- RESULTAT:
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/*
+- FUNCTION: PrintBlobs
+- FUNCTIONALITY: Prints some blob features in an ASCII file
+- PARAMETERS:
+- nom_fitxer: full path + filename to generate
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlobResult::PrintBlobs( char *nom_fitxer ) const
+{
+  double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud, 
+    externPerimeter, perimetreConvex, perimetre;
+  int i;
+  FILE *fitxer_sortida;
+
+  area      = GetSTLResult( CBlobGetArea());
+  perimetre = GetSTLResult( CBlobGetPerimeter());
+  exterior  = GetSTLResult( CBlobGetExterior());
+  mitjana   = GetSTLResult( CBlobGetMean());
+  compacitat = GetSTLResult(CBlobGetCompactness());
+  longitud  = GetSTLResult( CBlobGetLength());
+  externPerimeter = GetSTLResult( CBlobGetExternPerimeter());
+  perimetreConvex = GetSTLResult( CBlobGetHullPerimeter());
+
+  fitxer_sortida = fopen( nom_fitxer, "w" );
+
+  for(i=0; i<GetNumBlobs(); i++)
+  {
+    fprintf( fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n",
+      i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i] );
+  }
+  fclose( fitxer_sortida );
+
+}
+
+}
diff --git a/package_bgs/jmo/BlobResult.h b/package_bgs/jmo/BlobResult.h
new file mode 100644
index 0000000000000000000000000000000000000000..ef1fd40af258a83ee7eaba4786e3b750f936b276
--- /dev/null
+++ b/package_bgs/jmo/BlobResult.h
@@ -0,0 +1,213 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+ * Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/************************************************************************
+  			BlobResult.h
+  			
+FUNCIONALITAT: Definici� de la classe CBlobResult
+AUTOR: Inspecta S.L.
+MODIFICACIONS (Modificaci�, Autor, Data):
+
+FUNCTIONALITY: Definition of the CBlobResult class
+AUTHOR: Inspecta S.L.
+MODIFICATIONS (Modification, Author, Date):
+
+**************************************************************************/
+
+
+#if !defined(_CLASSE_BLOBRESULT_INCLUDED)
+#define _CLASSE_BLOBRESULT_INCLUDED
+
+#if _MSC_VER > 1000 
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "BlobLibraryConfiguration.h"
+#include <math.h>
+#include "cxcore.h"
+
+#ifdef MATRIXCV_ACTIU
+	#include "matrixCV.h"
+#else
+	// llibreria STL
+	#include "vector"
+	//! Vector de doubles
+	typedef std::vector<double> double_stl_vector;
+#endif
+
+#include <vector>		// vectors de la STL
+#include <functional>
+#include "blob.h"
+
+/**************************************************************************
+	Filtres / Filters
+**************************************************************************/
+
+//! accions que es poden fer amb els filtres
+//! Actions performed by a filter (include or exclude blobs)
+#define B_INCLUDE				1L
+#define B_EXCLUDE				2L
+
+//! condicions sobre els filtres
+//! Conditions to apply the filters
+#define B_EQUAL					3L
+#define B_NOT_EQUAL				4L
+#define B_GREATER				5L
+#define B_LESS					6L
+#define B_GREATER_OR_EQUAL		7L
+#define B_LESS_OR_EQUAL			8L
+#define B_INSIDE			    9L
+#define B_OUTSIDE			    10L
+
+
+/**************************************************************************
+	Excepcions / Exceptions
+**************************************************************************/
+
+//! Excepcions llen�ades per les funcions:
+#define EXCEPTION_BLOB_OUT_OF_BOUNDS	1000
+#define EXCEPCIO_CALCUL_BLOBS			1001
+
+namespace Blob
+{
+
+//! definici� de que es un vector de blobs
+typedef std::vector<CBlob*>	blob_vector;
+
+/** 
+	Classe que cont� un conjunt de blobs i permet extreure'n propietats 
+	o filtrar-los segons determinats criteris.
+	Class to calculate the blobs of an image and calculate some properties 
+	on them. Also, the class provides functions to filter the blobs using
+	some criteria.
+*/
+class CBlobResult  
+{
+public:
+
+	//! constructor estandard, crea un conjunt buit de blobs
+	//! Standard constructor, it creates an empty set of blobs
+	CBlobResult();
+	//! constructor a partir d'una imatge
+	//! Image constructor, it creates an object with the blobs of the image
+	CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments);
+	//! constructor de c�pia
+	//! Copy constructor
+	CBlobResult( const CBlobResult &source );
+	//! Destructor
+	virtual ~CBlobResult();
+
+	//! operador = per a fer assignacions entre CBlobResult
+	//! Assigment operator
+	CBlobResult& operator=(const CBlobResult& source);
+	//! operador + per concatenar dos CBlobResult
+	//! Addition operator to concatenate two sets of blobs
+	CBlobResult operator+( const CBlobResult& source );
+	
+	//! Afegeix un blob al conjunt
+	//! Adds a blob to the set of blobs
+	void AddBlob( CBlob *blob );
+
+#ifdef MATRIXCV_ACTIU
+	//! Calcula un valor sobre tots els blobs de la classe retornant una MatrixCV
+	//! Computes some property on all the blobs of the class
+	double_vector GetResult( funcio_calculBlob *evaluador ) const;
+#endif
+	//! Calcula un valor sobre tots els blobs de la classe retornant un std::vector<double>
+	//! Computes some property on all the blobs of the class
+	double_stl_vector GetSTLResult( funcio_calculBlob *evaluador ) const;
+	
+	//! Calcula un valor sobre un blob de la classe
+	//! Computes some property on one blob of the class
+	double GetNumber( int indexblob, funcio_calculBlob *evaluador ) const;
+
+	//! Retorna aquells blobs que compleixen les condicions del filtre en el destination 
+	//! Filters the blobs of the class using some property
+	void Filter(CBlobResult &dst,
+				int filterAction, funcio_calculBlob *evaluador, 
+				int condition, double lowLimit, double highLimit = 0 );
+			
+	//! Retorna l'en�ssim blob segons un determinat criteri
+	//! Sorts the blobs of the class acording to some criteria and returns the n-th blob
+	void GetNthBlob( funcio_calculBlob *criteri, int nBlob, CBlob &dst ) const;
+	
+	//! Retorna el blob en�ssim
+	//! Gets the n-th blob of the class ( without sorting )
+	CBlob GetBlob(int indexblob) const;
+	CBlob *GetBlob(int indexblob);
+	
+	//! Elimina tots els blobs de l'objecte
+	//! Clears all the blobs of the class
+	void ClearBlobs();
+
+	//! Escriu els blobs a un fitxer
+	//! Prints some features of all the blobs in a file
+	void PrintBlobs( char *nom_fitxer ) const;
+
+
+//Metodes GET/SET
+
+	//! Retorna el total de blobs
+	//! Gets the total number of blobs
+	int GetNumBlobs() const 
+	{ 
+		return(m_blobs.size()); 
+	}
+
+
+private:
+
+	//! Funci� per gestionar els errors
+	//! Function to manage the errors
+	void RaiseError(const int errorCode) const;
+
+protected:
+
+	//! Vector amb els blobs
+	//! Vector with all the blobs
+	blob_vector		m_blobs;
+};
+
+}
+
+#endif // !defined(_CLASSE_BLOBRESULT_INCLUDED)
+
diff --git a/package_bgs/jmo/CMultiLayerBGS.cpp b/package_bgs/jmo/CMultiLayerBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..134a24cf4963393c1dbe3b25910fdcfd591a22dc
--- /dev/null
+++ b/package_bgs/jmo/CMultiLayerBGS.cpp
@@ -0,0 +1,2128 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+// BackgroundSubtraction.cpp: implementation of the CMultiLayerBGS class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "CMultiLayerBGS.h"
+
+#include <ctime>						// clock
+#include <cstdlib>						// C standard library
+#include <cstdio>						// C I/O (for sscanf)
+#include <cstring>						// string manipulation
+#include <fstream>						// file I/O
+#include <cmath>						// math includes
+#include <iostream>                                             // I/O streams
+
+using namespace Blob;
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CMultiLayerBGS::CMultiLayerBGS() {
+  m_nMaxLBPModeNum = MAX_LBP_MODE_NUM;
+
+  m_fModeUpdatingLearnRate = MODE_UPDATING_LEARN_RATE;
+  m_f1_ModeUpdatingLearnRate = 1.0f - m_fModeUpdatingLearnRate;
+
+  m_fWeightUpdatingLearnRate = WEIGHT_UPDATING_LEARN_RATE;
+  m_f1_WeightUpdatingLearnRate = 1.0f - m_fWeightUpdatingLearnRate;
+
+  m_fRobustColorOffset = ROBUST_COLOR_OFFSET;
+
+  m_fLowInitialModeWeight = LOW_INITIAL_MODE_WEIGHT;
+
+  m_fPatternColorDistBgThreshold = PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD;
+  m_fPatternColorDistBgUpdatedThreshold = PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD;
+
+  m_fBackgroundModelPercent = BACKGROUND_MODEL_PERCENT;
+
+  m_nPatternDistSmoothNeigHalfSize = PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE;
+  m_fPatternDistConvGaussianSigma = PATTERN_DIST_CONV_GAUSSIAN_SIGMA;
+
+  m_fRobustShadowRate = ROBUST_SHADOW_RATE;
+  m_fRobustHighlightRate = ROBUST_HIGHLIGHT_RATE;
+
+  m_nCurImgFrameIdx = 0;
+
+  m_pBkMaskImg = NULL;
+
+  m_bUsedColorLBP = false;
+  m_bUsedGradImage = false;
+
+  m_fMinLBPBinaryProb = 0.1f;
+  m_f1_MinLBPBinaryProb = 1.0f - m_fMinLBPBinaryProb;
+
+  m_pOrgImg = m_pFgImg = m_pBgImg = m_pFgMaskImg = m_pBgDistImg = m_pEdgeImg = NULL;
+  m_ppOrgLBPImgs = NULL;
+
+  m_disableLearning = false;
+  m_fSigmaS = 3.0f;
+  m_fSigmaR = 0.1f;
+
+  m_fTextureWeight = 0.5f;
+  m_fColorWeight = 1.0f - m_fTextureWeight;
+
+  m_fWeightUpdatingConstant = 5.0f;
+
+  m_fReliableBackgroundModeWeight = 0.9f;
+
+  //m_fMinBgLayerWeight = m_fLowInitialModeWeight/50.0f;
+  m_fMinBgLayerWeight = 0.0001f;
+  //m_fMinBgLayerWeight = 0.88f;
+
+  m_fMinNoisedAngle = 3.0f / 180.0f * PI;
+  m_fMinNoisedAngleSine = sinf(m_fMinNoisedAngle);
+
+  m_fFrameDuration = 1.0f / 25.0f; /* 25 frames per second */
+
+  m_fModeUpdatingLearnRatePerSecond = 0.2f;
+  m_fWeightUpdatingLearnRatePerSecond = 0.2f;
+
+  m_pROI = NULL;
+}
+
+CMultiLayerBGS::~CMultiLayerBGS() {
+  int img_length = m_cvImgSize.height * m_cvImgSize.width;
+  PixelLBPStruct* PLBP = m_pPixelLBPs;
+  for (int yx = 0; yx < img_length; yx++) {
+    delete (*PLBP).cur_intensity;
+    delete (*PLBP).cur_pattern;
+    delete (*PLBP).lbp_idxes;
+    for (int a = 0; a < m_nMaxLBPModeNum; a++) {
+      delete (*PLBP).LBPs[a].bg_intensity;
+      delete (*PLBP).LBPs[a].max_intensity;
+      delete (*PLBP).LBPs[a].min_intensity;
+      delete (*PLBP).LBPs[a].bg_pattern;
+    }
+    delete (*PLBP).LBPs;
+    PLBP++;
+  }
+  delete m_pPixelLBPs;
+
+  /* release memories */
+  if (m_pFgImg != NULL)
+    cvReleaseImage(&m_pFgImg);
+  if (m_pBgImg != NULL)
+    cvReleaseImage(&m_pBgImg);
+  if (m_pBgDistImg != NULL)
+    cvReleaseImage(&m_pBgDistImg);
+  if (m_ppOrgLBPImgs != NULL) {
+    int a;
+    for (a = 0; a < m_nLBPImgNum; a++)
+      cvReleaseImage(&m_ppOrgLBPImgs[a]);
+    delete [] m_ppOrgLBPImgs;
+  }
+  if (m_pEdgeImg)
+    cvReleaseImage(&m_pEdgeImg);
+}
+
+void CMultiLayerBGS::ResetAllParameters() {
+  m_f1_ModeUpdatingLearnRate = 1.0f - m_fModeUpdatingLearnRate;
+  m_f1_WeightUpdatingLearnRate = 1.0f - m_fWeightUpdatingLearnRate;
+  m_f1_MinLBPBinaryProb = 1.0f - m_fMinLBPBinaryProb;
+
+  m_fColorWeight = 1.0f - m_fTextureWeight;
+
+  m_fMinNoisedAngleSine = sinf(m_fMinNoisedAngle);
+
+  //m_fMinBgLayerWeight = m_fLowInitialModeWeight/50.0f;
+  m_fMinBgLayerWeight = 0.0001f;
+
+  m_cLBP.m_fRobustWhiteNoise = m_fRobustColorOffset;
+}
+
+void CMultiLayerBGS::MergeImages(int num, ...) {
+  if (num < 1 || num > 9) {
+    printf("Error: the number %d of merging images.\n", num);
+    exit(0);
+  }
+
+  int nCols = 0, nRows = 0;
+  switch (num) {
+  case 1: nCols = nRows = 1;
+    break;
+  case 2: nCols = 1;
+    nRows = 2;
+    break;
+  case 3:
+  case 4: nCols = 2;
+    nRows = 2;
+    break;
+  case 5:
+  case 6: nCols = 3;
+    nRows = 2;
+    break;
+  case 7:
+  case 8:
+  case 9: nCols = 3;
+    nRows = 3;
+    break;
+  }
+
+  int a, b;
+
+  IplImage** ppIplImg = new IplImage*[num + 1];
+
+  va_list arg_ptr;
+  va_start(arg_ptr, num);
+  for (a = 0; a < num + 1; a++)
+    ppIplImg[a] = va_arg(arg_ptr, IplImage*);
+  va_end(arg_ptr);
+
+  CvRect imgROIRect;
+  CvSize imgSize = cvGetSize(ppIplImg[0]);
+  if (ppIplImg[num] == NULL) { // for the output video
+    ppIplImg[num] = cvCreateImage(cvSize(imgSize.width*nCols, imgSize.height * nRows), IPL_DEPTH_8U, ppIplImg[0]->nChannels);
+  }
+
+  int img_idx = 0;
+  for (a = 0; a < nRows; a++)
+    for (b = 0; b < nCols; b++) {
+      if (img_idx >= num)
+        break;
+
+      imgROIRect = cvRect(b * imgSize.width, a * imgSize.height, imgSize.width, imgSize.height);
+
+      cvSetImageROI(ppIplImg[num], imgROIRect);
+      cvCopyImage(ppIplImg[img_idx++], ppIplImg[num]);
+      cvResetImageROI(ppIplImg[num]);
+    }
+
+    delete [] ppIplImg;
+}
+
+void CMultiLayerBGS::Update_MAX_MIN_Intensity(unsigned char *cur_intensity, float *max_intensity, float *min_intensity) {
+  int a;
+  float curI;
+  for (a = 0; a < m_nChannel; a++) {
+    curI = (float) cur_intensity[a];
+
+    min_intensity[a] = MIN(curI, min_intensity[a]);
+    max_intensity[a] = MAX(curI, max_intensity[a]);
+  }
+}
+
+void CMultiLayerBGS::UpdateBgPixelColor(unsigned char *cur_intensity, float* bg_intensity) {
+  int a;
+  for (a = 0; a < m_nChannel; a++)
+    bg_intensity[a] = m_f1_ModeUpdatingLearnRate * bg_intensity[a] + m_fModeUpdatingLearnRate * (float) cur_intensity[a];
+}
+
+void CMultiLayerBGS::UpdateBgPixelPattern(float *cur_pattern, float *bg_pattern) {
+  int a;
+  for (a = 0; a < m_nLBPLength; a++)
+    bg_pattern[a] = m_f1_ModeUpdatingLearnRate * bg_pattern[a] + m_fModeUpdatingLearnRate * cur_pattern[a];
+}
+
+/* sort everything inbetween `low' <-> `high' */
+void CMultiLayerBGS::QuickSort(float *pData, unsigned short *pIdxes, long low, long high, bool bAscent) {
+  long i = low;
+  long j = high;
+  float y = 0;
+  int idx = 0;
+
+  /* compare value */
+  float z = pData[(low + high) / 2];
+
+  /* partition */
+  do {
+    if (bAscent) {
+      /* find member above ... */
+      while (pData[i] < z) i++;
+
+      /* find element below ... */
+      while (pData[j] > z) j--;
+    } else {
+      /* find member below ... */
+      while (pData[i] > z) i++;
+
+      /* find element above ... */
+      while (pData[j] < z) j--;
+    }
+
+    if (i <= j) {
+      /* swap two elements */
+      y = pData[i];
+      pData[i] = pData[j];
+      pData[j] = y;
+
+      idx = pIdxes[i];
+      pIdxes[i] = pIdxes[j];
+      pIdxes[j] = idx;
+
+      i++;
+      j--;
+    }
+  } while (i <= j);
+
+  /* recurse */
+  if (low < j)
+    QuickSort(pData, pIdxes, low, j, bAscent);
+
+  if (i < high)
+    QuickSort(pData, pIdxes, i, high, bAscent);
+}
+
+float CMultiLayerBGS::DistLBP(LBPStruct *LBP1, LBPStruct *LBP2) {
+  int a;
+
+  float pattern_dist = 0;
+  for (a = 0; a < m_nLBPLength; a++) {
+    pattern_dist = fabsf(LBP1->bg_pattern[a] - LBP1->bg_pattern[a]);
+  }
+  pattern_dist /= (float) m_nLBPLength;
+
+  float color_dist = 0;
+  for (a = 0; a < m_nChannel; a++) {
+    color_dist += fabsf((float) LBP1->bg_intensity[a]-(float) LBP2->bg_intensity[a]);
+  }
+  color_dist /= 3.0f * 125.0f;
+
+  //return MAX(pattern_dist, color_dist);
+  return color_dist;
+}
+
+void CMultiLayerBGS::SetNewImage(IplImage *new_img, CvRect *roi) {
+  m_pOrgImg = new_img;
+  m_pROI = roi;
+  if (roi && (roi->width <= 0 || roi->height <= 0))
+    return;
+
+  if (roi) {
+    cvSetImageROI(m_pOrgImg, *roi);
+    for (int a = 0; a < m_nLBPImgNum; a++)
+      cvSetImageROI(m_ppOrgLBPImgs[a], *roi);
+  }
+
+  switch (m_nLBPImgNum) {
+  case 1:
+    cvCvtColor(m_pOrgImg, m_ppOrgLBPImgs[0], CV_BGR2GRAY);
+    break;
+  case 2:
+    cvCvtColor(m_pOrgImg, m_ppOrgLBPImgs[0], CV_BGR2GRAY);
+    ComputeGradientImage(m_ppOrgLBPImgs[0], m_ppOrgLBPImgs[1], false);
+    break;
+  case 3:
+    cvSplit(m_pOrgImg, m_ppOrgLBPImgs[0], m_ppOrgLBPImgs[1], m_ppOrgLBPImgs[2], NULL);
+    break;
+  case 4:
+    cvSplit(m_pOrgImg, m_ppOrgLBPImgs[0], m_ppOrgLBPImgs[1], m_ppOrgLBPImgs[2], NULL);
+    ComputeGradientImage(m_ppOrgLBPImgs[0], m_ppOrgLBPImgs[3], false);
+    break;
+  }
+
+  if (roi) {
+    cvResetImageROI(m_pOrgImg);
+    for (int a = 0; a < m_nLBPImgNum; a++)
+      cvResetImageROI(m_ppOrgLBPImgs[a]);
+  }
+  m_cLBP.SetNewImages(m_ppOrgLBPImgs);
+
+  m_nCurImgFrameIdx++;
+}
+
+void CMultiLayerBGS::SetBkMaskImage(IplImage *mask_img) {
+  if (m_pBkMaskImg == NULL) {
+    m_pBkMaskImg = cvCreateImage(cvGetSize(mask_img), mask_img->depth, mask_img->nChannels);
+  }
+  cvCopyImage(mask_img, m_pBkMaskImg);
+}
+
+void CMultiLayerBGS::BackgroundSubtractionProcess() {
+  CvRect *roi = m_pROI;
+
+  if (roi && (roi->width <= 0 || roi->height <= 0))
+    return;
+  LBPStruct* LBPs;
+  unsigned int bg_num;
+  float* cur_pattern;
+  unsigned char* cur_intensity;
+  int a, b;
+  unsigned int lbp_num;
+  unsigned short* lbp_idxes;
+  unsigned short cur_lbp_idx;
+  bool bBackgroundUpdating;
+
+  PixelLBPStruct *PLBP = m_pPixelLBPs;
+
+  bool bFirstFrame = (PLBP[0].num == 0);
+  float best_match_bg_dist, bg_pattern_dist, bg_color_dist, bg_pattern_color_dist;
+
+  // compute the local binary pattern
+  if (m_fTextureWeight > 0)
+    m_cLBP.ComputeLBP(PLBP, roi);
+
+  LBPStruct* curLBP;
+
+  int data_length;
+
+  if (roi)
+    data_length = roi->width * roi->height;
+  else
+    data_length = m_cvImgSize.width * m_cvImgSize.height;
+
+  int best_match_idx;
+
+  COpencvDataConversion<uchar, uchar> ODC1;
+  if (roi) {
+    cvSetImageROI(m_pBkMaskImg, *roi);
+    cvSetImageROI(m_pOrgImg, *roi);
+  }
+  uchar *_mask = ODC1.GetImageData(m_pBkMaskImg);
+  uchar *_org_intensity = ODC1.GetImageData(m_pOrgImg);
+
+  if (roi) {
+    cvResetImageROI(m_pBkMaskImg);
+    cvResetImageROI(m_pOrgImg);
+  }
+
+  COpencvDataConversion<float, float> ODC2;
+  float *_bg_dist = new float[data_length];
+
+  uchar *mask = _mask;
+  uchar *org_intensity = _org_intensity;
+  float *bg_dist = _bg_dist;
+
+  bool removed_modes[10];
+
+  // scanning the point via first x-axis and then y-axis
+  int x, y;
+
+  for (y = 0; y < (roi ? roi->height : m_cvImgSize.height); y++) {
+    if (roi)
+      PLBP = m_pPixelLBPs + (roi->y + y) * m_cvImgSize.width + roi->x;
+    else
+      PLBP = m_pPixelLBPs + y * m_cvImgSize.width;
+
+    for (x = 0; x < (roi ? roi->width : m_cvImgSize.width); x++) {
+      // check whether the current pixel is the pixel to be modeled
+      if (*mask++ == 0) {
+        PLBP++;
+        *bg_dist++ = 0.0f; //m_fPatternColorDistBgThreshold*1.01f;
+        org_intensity += m_nChannel;
+        continue;
+      }
+
+      // removing the background layers
+      if (!m_disableLearning) {
+        RemoveBackgroundLayers(PLBP);
+      }
+
+      // check whether the current image is the first image
+      bFirstFrame = ((*PLBP).num == 0);
+
+      // get lbp information
+      lbp_num = (*PLBP).num;
+      LBPs = (*PLBP).LBPs;
+      lbp_idxes = (*PLBP).lbp_idxes;
+
+      (*PLBP).cur_bg_layer_no = 0;
+
+      // set the current pixel's intensity
+      cur_intensity = (*PLBP).cur_intensity;
+      for (a = 0; a < m_nChannel; a++)
+        cur_intensity[a] = *org_intensity++;
+
+      // get the current lbp pattern
+      cur_pattern = (*PLBP).cur_pattern;
+
+      // first check whether the pixel is background or foreground and then update the background pattern model
+      if (lbp_num == 0) { // empty pattern list
+        curLBP = (&(LBPs[0]));
+        for (a = 0; a < m_nLBPLength; a++) {
+          curLBP->bg_pattern[a] = (float) cur_pattern[a];
+        }
+
+        curLBP->bg_layer_num = 0;
+        curLBP->weight = m_fLowInitialModeWeight;
+        curLBP->max_weight = m_fLowInitialModeWeight;
+
+        curLBP->first_time = m_nCurImgFrameIdx;
+        curLBP->last_time = m_nCurImgFrameIdx;
+        curLBP->freq = 1;
+
+        (*PLBP).matched_mode_first_time = (float) m_nCurImgFrameIdx;
+
+        for (a = 0; a < m_nChannel; a++) {
+          curLBP->bg_intensity[a] = (float) cur_intensity[a];
+          curLBP->min_intensity[a] = (float) cur_intensity[a];
+          curLBP->max_intensity[a] = (float) cur_intensity[a];
+        }
+
+        lbp_idxes[0] = 0;
+
+        lbp_num++;
+        (*PLBP).num = 1;
+        (*PLBP).bg_num = 1;
+
+        PLBP++;
+        *bg_dist++ = 0.0f;
+        continue;
+      } else { // not empty pattern list
+        /*
+        // remove the background layers
+        // end of removing the background layer
+        */
+
+        best_match_idx = -1;
+        best_match_bg_dist = 999.0f;
+
+        // find the best match
+        for (a = 0; a < (int) lbp_num; a++) {
+          // get the current index for lbp pattern
+          cur_lbp_idx = lbp_idxes[a];
+
+          // get the current LBP pointer
+          curLBP = &(LBPs[cur_lbp_idx]);
+
+          // compute the background probability based on lbp pattern
+          bg_pattern_dist = 0.0f;
+          if (m_fTextureWeight > 0)
+            bg_pattern_dist = CalPatternBgDist(cur_pattern, curLBP->bg_pattern);
+
+          // compute the color invariant probability based on RGB color
+          bg_color_dist = 0.0f;
+          if (m_fColorWeight > 0)
+            bg_color_dist = CalColorBgDist(cur_intensity, curLBP->bg_intensity, curLBP->max_intensity, curLBP->min_intensity);
+
+          // compute the joint background probability
+          //bg_pattern_color_dist = sqrtf(bg_color_dist*bg_pattern_dist);
+
+          //UpdatePatternColorDistWeights(cur_pattern, curLBP->bg_pattern);
+
+          bg_pattern_color_dist = m_fColorWeight * bg_color_dist + m_fTextureWeight*bg_pattern_dist;
+          //bg_pattern_color_dist = MAX(bg_color_dist, bg_pattern_dist);
+
+          //bg_pattern_color_dist = 1.0f - (1.0f-bg_color_dist)*(1.0-bg_pattern_dist);
+          //bg_pattern_color_dist = bg_pattern_dist;
+
+          //bg_pattern_color_dist = bg_color_dist;
+
+          if (bg_pattern_color_dist < best_match_bg_dist) {
+            best_match_bg_dist = bg_pattern_color_dist;
+            best_match_idx = a;
+          }
+        }
+
+        bg_num = (*PLBP).bg_num;
+
+        // check
+        bBackgroundUpdating = ((best_match_bg_dist < m_fPatternColorDistBgUpdatedThreshold));
+
+        // reset the weight of the mode
+        if (best_match_idx >= (int) bg_num && LBPs[lbp_idxes[best_match_idx]].max_weight < m_fReliableBackgroundModeWeight) // found not in the background models
+          best_match_bg_dist = MAX(best_match_bg_dist, m_fPatternColorDistBgThreshold * 2.5f);
+
+        *bg_dist = best_match_bg_dist;
+      }
+      if (m_disableLearning) {
+        // no creation or update when learning is disabled
+      } else if (!bBackgroundUpdating) { // no match
+
+        for (a = 0; a < (int) lbp_num; a++) { // decrease the weights
+          curLBP = &(LBPs[lbp_idxes[a]]);
+          curLBP->weight *= (1.0f - m_fWeightUpdatingLearnRate / (1.0f + m_fWeightUpdatingConstant * curLBP->max_weight));
+        }
+
+        if ((int) lbp_num < m_nMaxLBPModeNum) { // add a new pattern
+          // find the pattern index for addition
+          int add_lbp_idx = 0;
+          bool bFound;
+          for (a = 0; a < m_nMaxLBPModeNum; a++) {
+            bFound = true;
+            for (b = 0; b < (int) lbp_num; b++)
+              bFound &= (a != lbp_idxes[b]);
+            if (bFound) {
+              add_lbp_idx = a;
+              break;
+            }
+          }
+          curLBP = &(LBPs[add_lbp_idx]);
+
+          curLBP->first_time = m_nCurImgFrameIdx;
+          curLBP->last_time = m_nCurImgFrameIdx;
+          curLBP->freq = 1;
+          curLBP->layer_time = -1;
+
+          (*PLBP).matched_mode_first_time = (float) m_nCurImgFrameIdx;
+
+          for (a = 0; a < m_nLBPLength; a++) {
+            curLBP->bg_pattern[a] = (float) cur_pattern[a];
+          }
+
+          curLBP->bg_layer_num = 0;
+          curLBP->weight = m_fLowInitialModeWeight;
+          curLBP->max_weight = m_fLowInitialModeWeight;
+
+          for (a = 0; a < m_nChannel; a++) {
+            curLBP->bg_intensity[a] = (float) cur_intensity[a];
+            curLBP->min_intensity[a] = (float) cur_intensity[a];
+            curLBP->max_intensity[a] = (float) cur_intensity[a];
+          }
+
+          lbp_idxes[lbp_num] = add_lbp_idx;
+
+          lbp_num++;
+          (*PLBP).num = lbp_num;
+        } else { // replacing the pattern with the minimal weight
+          // find the replaced pattern index
+          /*
+          int rep_pattern_idx = -1;
+          for ( a = m_nLBPLength-1 ; a >= 0 ; a-- ) {
+          if ( LBPs[lbp_idxes[a]].bg_layer_num == 0 )
+          rep_pattern_idx = lbp_idxes[a];
+          }
+          if ( rep_pattern_idx < 0 ) {
+          rep_pattern_idx = lbp_idxes[m_nMaxLBPModeNum-1];
+          for ( a = 0 ; a < m_nLBPLength ; a++ ) {
+          if ( LBPs[lbp_idxes[a]].bg_layer_num > LBPs[rep_pattern_idx].bg_layer_num )
+          LBPs[lbp_idxes[a]].bg_layer_num--;
+          }
+          }
+          */
+          int rep_pattern_idx = lbp_idxes[m_nMaxLBPModeNum - 1];
+
+          curLBP = &(LBPs[rep_pattern_idx]);
+
+          curLBP->first_time = m_nCurImgFrameIdx;
+          curLBP->last_time = m_nCurImgFrameIdx;
+          curLBP->freq = 1;
+          curLBP->layer_time = -1;
+
+          (*PLBP).matched_mode_first_time = (float) m_nCurImgFrameIdx;
+
+          for (a = 0; a < m_nLBPLength; a++) {
+            curLBP->bg_pattern[a] = (float) cur_pattern[a];
+          }
+
+          curLBP->bg_layer_num = 0;
+          curLBP->weight = m_fLowInitialModeWeight;
+          curLBP->max_weight = m_fLowInitialModeWeight;
+
+          for (a = 0; a < m_nChannel; a++) {
+            curLBP->bg_intensity[a] = (float) cur_intensity[a];
+            curLBP->min_intensity[a] = (float) cur_intensity[a];
+            curLBP->max_intensity[a] = (float) cur_intensity[a];
+          }
+        }
+      } else { // find match
+        // updating the background pattern model
+        cur_lbp_idx = lbp_idxes[best_match_idx];
+        curLBP = &(LBPs[cur_lbp_idx]);
+
+        curLBP->first_time = MAX(MIN(curLBP->first_time, m_nCurImgFrameIdx), 0);
+        (*PLBP).matched_mode_first_time = curLBP->first_time;
+
+        curLBP->last_time = m_nCurImgFrameIdx;
+        curLBP->freq++;
+
+        if (m_fColorWeight > 0) {
+          // update the color information
+          UpdateBgPixelColor(cur_intensity, curLBP->bg_intensity);
+          // update the MAX and MIN color intensity
+          Update_MAX_MIN_Intensity(cur_intensity, curLBP->max_intensity, curLBP->min_intensity);
+        }
+
+        // update the texture information
+        if (m_fTextureWeight > 0)
+          UpdateBgPixelPattern(cur_pattern, curLBP->bg_pattern);
+
+
+        // increase the weight of the best matched mode
+        float increasing_weight_factor = m_fWeightUpdatingLearnRate * (1.0f + m_fWeightUpdatingConstant * curLBP->max_weight);
+        curLBP->weight = (1.0f - increasing_weight_factor) * curLBP->weight + increasing_weight_factor; //*expf(-best_match_dist/m_fPatternColorDistBgThreshold);
+
+        // update the maximal weight for the best matched mode
+        curLBP->max_weight = MAX(curLBP->weight, curLBP->max_weight);
+
+        // calculate the number of background layer
+        if (curLBP->bg_layer_num > 0) {
+          bool removed_bg_layers = false;
+          if (curLBP->weight > curLBP->max_weight * 0.2f) {
+            for (a = 0; a < (int) lbp_num; a++) {
+              removed_modes[a] = false;
+              if (LBPs[lbp_idxes[a]].bg_layer_num > curLBP->bg_layer_num &&
+                LBPs[lbp_idxes[a]].weight < LBPs[lbp_idxes[a]].max_weight * 0.9f) { /* remove layers */
+                  //LBPs[lbp_idxes[a]].bg_layer_num = 0;
+                  removed_modes[a] = true;
+                  removed_bg_layers = true;
+              }
+            }
+          }
+
+          if (removed_bg_layers) {
+            RemoveBackgroundLayers(PLBP, removed_modes);
+            lbp_num = (*PLBP).num;
+          }
+        } else if (curLBP->max_weight > m_fReliableBackgroundModeWeight && curLBP->bg_layer_num == 0) {
+          int max_bg_layer_num = LBPs[lbp_idxes[0]].bg_layer_num;
+          for (a = 1; a < (int) lbp_num; a++)
+            max_bg_layer_num = MAX(max_bg_layer_num, LBPs[lbp_idxes[a]].bg_layer_num);
+          curLBP->bg_layer_num = max_bg_layer_num + 1;
+          curLBP->layer_time = m_nCurImgFrameIdx;
+        }
+
+        (*PLBP).cur_bg_layer_no = curLBP->bg_layer_num;
+
+        // decrease the weights of non-best matched modes
+        for (a = 0; a < (int) lbp_num; a++) {
+          if (a != best_match_idx) {
+            curLBP = &(LBPs[lbp_idxes[a]]);
+            curLBP->weight *= (1.0f - m_fWeightUpdatingLearnRate / (1.0f + m_fWeightUpdatingConstant * curLBP->max_weight));
+          }
+        }
+      }
+
+      // sort the list of modes based on the weights of modes
+      if ((int) lbp_num > 1 && !m_disableLearning) {
+        float weights[100], tot_weights = 0;
+        for (a = 0; a < (int) lbp_num; a++) {
+          weights[a] = LBPs[lbp_idxes[a]].weight;
+          tot_weights += weights[a];
+        }
+
+        // sort weights in the descent order
+        QuickSort(weights, lbp_idxes, 0, (int) lbp_num - 1, false);
+
+        // calculate the first potential background modes number, bg_num
+        float threshold_weight = m_fBackgroundModelPercent*tot_weights;
+        tot_weights = 0;
+        for (a = 0; a < (int) lbp_num; a++) {
+          tot_weights += LBPs[lbp_idxes[a]].weight;
+          if (tot_weights > threshold_weight) {
+            bg_num = a + 1;
+            break;
+          }
+        }
+        (*PLBP).bg_num = bg_num;
+      }
+
+      PLBP++;
+      bg_dist++;
+    }
+  }
+
+  if (bFirstFrame) { // check whether it is the first frame for background modeling
+    if (m_pFgMaskImg)
+      cvSetZero(m_pFgMaskImg);
+    cvSetZero(m_pBgDistImg);
+  } else {
+    // set the image data
+    if (roi) {
+      cvSetZero(m_pBgDistImg);
+      cvSetImageROI(m_pBgDistImg, *roi);
+    }
+    ODC2.SetImageData(m_pBgDistImg, _bg_dist);
+
+    // do gaussian smooth
+    if (m_nPatternDistSmoothNeigHalfSize >= 0)
+      cvSmooth(m_pBgDistImg, m_pBgDistImg, CV_GAUSSIAN, (2 * m_nPatternDistSmoothNeigHalfSize + 1), (2 * m_nPatternDistSmoothNeigHalfSize + 1), m_fPatternDistConvGaussianSigma);
+
+    if (roi)
+      cvResetImageROI(m_pBgDistImg);
+#ifdef LINUX_BILATERAL_FILTER
+    // do cross bilateral filter
+    fprintf(stderr, "%f %f\n", m_fSigmaS, m_fSigmaR);
+    if (m_fSigmaS > 0 && m_fSigmaR > 0) {
+      GetFloatEdgeImage(m_ppOrgLBPImgs[0], m_pEdgeImg);
+      //ComputeGradientImage(m_ppOrgLBPImgs[0], m_pEdgeImg, true);
+      m_cCrossBF.SetNewImages(m_pBgDistImg, m_pEdgeImg);
+      m_cCrossBF.FastCrossBF();
+      m_cCrossBF.GetFilteredImage(m_pBgDistImg);
+    }
+#endif
+
+    // get the foreground mask by thresholding
+    if (m_pFgMaskImg)
+      cvThreshold(m_pBgDistImg, m_pFgMaskImg, m_fPatternColorDistBgThreshold, 255, CV_THRESH_BINARY);
+
+    // get the foreground probability image (uchar)
+    if (m_pFgProbImg)
+      GetForegroundProbabilityImage(m_pFgProbImg);
+
+    // do post-processing
+    //Postprocessing();
+  }
+
+  // release memories
+  delete [] _mask;
+  delete [] _bg_dist;
+  delete [] _org_intensity;
+}
+
+void CMultiLayerBGS::GetBackgroundImage(IplImage *bk_img) {
+  IplImage *bg_img = m_pBgImg;
+  uchar *c1;
+  float *c2;
+  int bg_img_idx;
+  int channel;
+  int img_length = m_cvImgSize.height * m_cvImgSize.width;
+  int yx;
+
+  COpencvDataConversion<uchar, uchar> ODC;
+  uchar *org_data = ODC.GetImageData(bg_img);
+  c1 = org_data;
+
+  //c1 = (uchar*)(bg_img->imageData);
+
+  PixelLBPStruct* PLBP = m_pPixelLBPs;
+
+  for (yx = 0; yx < img_length; yx++) {
+    // the newest background image
+    bg_img_idx = (*PLBP).lbp_idxes[0];
+    if ((*PLBP).num == 0) {
+      for (channel = 0; channel < m_nChannel; channel++)
+        *c1++ = 0;
+    } else {
+      c2 = (*PLBP).LBPs[bg_img_idx].bg_intensity;
+      for (channel = 0; channel < m_nChannel; channel++)
+        *c1++ = cvRound(*c2++);
+    }
+    PLBP++;
+  }
+
+  ODC.SetImageData(bg_img, org_data);
+  delete [] org_data;
+
+  cvCopyImage(m_pBgImg, bk_img);
+}
+
+void CMultiLayerBGS::GetForegroundImage(IplImage *fg_img, CvScalar bg_color) {
+  if (m_pROI && (m_pROI->width <= 0 || m_pROI->height <= 0))
+    return;
+  IplImage* org_img;
+  IplImage* fg_mask_img; // the Mat pointer of the foreground mask matrices at different levels
+
+  org_img = m_pOrgImg;
+  fg_mask_img = m_pFgMaskImg;
+
+  cvSet(fg_img, bg_color);
+  if (m_pROI) {
+    cvSetImageROI(org_img, *m_pROI);
+    cvSetImageROI(fg_img, *m_pROI);
+    cvSetImageROI(fg_mask_img, *m_pROI);
+    cvCopy(org_img, fg_img, fg_mask_img);
+    cvResetImageROI(org_img);
+    cvResetImageROI(fg_img);
+    cvResetImageROI(fg_mask_img);
+  } else
+    cvCopy(org_img, fg_img, fg_mask_img);
+}
+
+void CMultiLayerBGS::GetForegroundMaskImage(IplImage *fg_mask_img) {
+  if (m_pROI && (m_pROI->width <= 0 || m_pROI->height <= 0))
+    return;
+
+  //cvCopyImage(m_pFgMaskImg, fg_mask_img);
+  if (m_pROI) {
+    cvSetImageROI(m_pFgMaskImg, *m_pROI);
+    cvSetImageROI(fg_mask_img, *m_pROI);
+    cvThreshold(m_pFgMaskImg, fg_mask_img, 0, 255, CV_THRESH_BINARY);
+    cvResetImageROI(m_pFgMaskImg);
+    cvResetImageROI(fg_mask_img);
+  } else
+    cvThreshold(m_pFgMaskImg, fg_mask_img, 0, 255, CV_THRESH_BINARY);
+}
+
+void CMultiLayerBGS::GetForegroundMaskMap(CvMat *fg_mask_mat) {
+  COpencvDataConversion<uchar, uchar> ODC;
+  ODC.ConvertData(m_pFgMaskImg, fg_mask_mat);
+}
+
+void CMultiLayerBGS::GetCurrentBackgroundDistMap(CvMat *bk_dist_map) {
+  cvCopy(m_pBgDistImg, bk_dist_map);
+}
+
+void CMultiLayerBGS::Initialization(IplImage *first_img, int lbp_level_num, float *radiuses, int *neig_pt_nums) {
+  int a;
+
+  m_nLBPLength = 0;
+  m_nLBPLevelNum = lbp_level_num;
+  for (a = 0; a < lbp_level_num; a++) {
+    m_nLBPLength += neig_pt_nums[a];
+    m_pLBPRadiuses[a] = radiuses[a];
+    m_pLBPMeigPointNums[a] = neig_pt_nums[a];
+  }
+
+  m_pFgImg = NULL;
+  m_pFgMaskImg = NULL;
+  m_pBgDistImg = NULL;
+  m_pOrgImg = NULL;
+  m_pBgImg = NULL;
+  m_ppOrgLBPImgs = NULL;
+  m_pFgProbImg = NULL;
+
+  m_cvImgSize = cvGetSize(first_img);
+
+  m_nChannel = first_img->nChannels;
+
+  m_pOrgImg = first_img;
+
+  if (m_bUsedColorLBP && m_bUsedGradImage)
+    m_nLBPImgNum = 4;
+  else if (m_bUsedColorLBP && !m_bUsedGradImage)
+    m_nLBPImgNum = 3;
+  else if (!m_bUsedColorLBP && m_bUsedGradImage)
+    m_nLBPImgNum = 2;
+  else
+    m_nLBPImgNum = 1;
+
+  m_nLBPLength *= m_nLBPImgNum;
+
+  m_ppOrgLBPImgs = new IplImage*[m_nLBPImgNum];
+  for (a = 0; a < m_nLBPImgNum; a++)
+    m_ppOrgLBPImgs[a] = cvCreateImage(m_cvImgSize, IPL_DEPTH_8U, 1);
+
+  m_pBgImg = cvCreateImage(m_cvImgSize, IPL_DEPTH_8U, m_nChannel);
+  m_pFgImg = cvCreateImage(m_cvImgSize, IPL_DEPTH_8U, m_nChannel);
+  m_pEdgeImg = cvCreateImage(m_cvImgSize, IPL_DEPTH_32F, 1);
+  m_pBgDistImg = cvCreateImage(m_cvImgSize, IPL_DEPTH_32F, 1);
+
+  ResetAllParameters();
+
+  int img_length = m_cvImgSize.height * m_cvImgSize.width;
+  m_pPixelLBPs = new PixelLBPStruct[img_length];
+  PixelLBPStruct* PLBP = m_pPixelLBPs;
+  int yx;
+  for (yx = 0; yx < img_length; yx++) {
+    (*PLBP).cur_intensity = new unsigned char[m_nChannel];
+    (*PLBP).cur_pattern = new float[m_nLBPLength];
+    (*PLBP).LBPs = new LBPStruct[m_nMaxLBPModeNum];
+    (*PLBP).lbp_idxes = new unsigned short[m_nMaxLBPModeNum];
+    (*PLBP).lbp_idxes[0] = 0;
+    (*PLBP).num = 0;
+    (*PLBP).cur_bg_layer_no = 0;
+    (*PLBP).matched_mode_first_time = 0;
+    for (a = 0; a < m_nMaxLBPModeNum; a++) {
+      (*PLBP).LBPs[a].bg_intensity = new float[m_nChannel];
+      (*PLBP).LBPs[a].max_intensity = new float[m_nChannel];
+      (*PLBP).LBPs[a].min_intensity = new float[m_nChannel];
+      (*PLBP).LBPs[a].bg_pattern = new float[m_nLBPLength];
+      (*PLBP).LBPs[a].first_time = -1;
+      (*PLBP).LBPs[a].last_time = -1;
+      (*PLBP).LBPs[a].freq = -1;
+      (*PLBP).LBPs[a].layer_time = -1;
+    }
+    PLBP++;
+  }
+
+  m_pBkMaskImg = cvCreateImage(m_cvImgSize, IPL_DEPTH_8U, 1);
+  cvSet(m_pBkMaskImg, cvScalar(1));
+
+  m_cLBP.Initialization(m_ppOrgLBPImgs, m_nLBPImgNum, lbp_level_num, radiuses, neig_pt_nums, m_fRobustColorOffset);
+
+#ifdef LINUX_BILATERAL_FILTER
+  if (m_fSigmaS > 0 && m_fSigmaR > 0)
+    m_cCrossBF.Initialization(m_pBgDistImg, m_pBgDistImg, m_fSigmaS, m_fSigmaR);
+#endif
+}
+
+float CMultiLayerBGS::CalPatternBgDist(float *cur_pattern, float *bg_pattern) {
+  float bg_hamming_dist = 0;
+  int a;
+  for (a = 0; a < m_nLBPLength; a++)
+    bg_hamming_dist += fabsf(cur_pattern[a] - bg_pattern[a]) > m_f1_MinLBPBinaryProb;
+
+  bg_hamming_dist /= (float) m_nLBPLength;
+
+  return bg_hamming_dist;
+}
+
+float CMultiLayerBGS::CalColorBgDist(uchar *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity) {
+  float noised_angle, range_dist, bg_color_dist;
+
+  range_dist = CalColorRangeDist(cur_intensity, bg_intensity, max_intensity, min_intensity, m_fRobustShadowRate, m_fRobustHighlightRate);
+
+  if (range_dist == 1.0f)
+    bg_color_dist = range_dist;
+  else {
+    noised_angle = CalVectorsNoisedAngle(bg_intensity, cur_intensity, MAX(m_fRobustColorOffset, 5.0f), m_nChannel);
+    bg_color_dist = (1.0f - expf(-100.0f * noised_angle * noised_angle));
+  }
+
+  //float bg_color_dist = (expf(-100.0f*noised_angle*noised_angle)*(1.0f-range_dist);
+
+  //float bg_color_dist =  0.5f*(1.0f-expf(-noised_angle*noised_angle/0.005f)) + 0.5f*range_dist;
+  //float bg_color_dist =  MAX((float)(noised_angle>0.08f), range_dist);
+
+  return bg_color_dist;
+}
+
+void CMultiLayerBGS::ComputeGradientImage(IplImage *src, IplImage *dst, bool bIsFloat) {
+  if (src->nChannels != 1 || dst->nChannels != 1) {
+    printf("Input images error for computing gradient images!");
+    exit(1);
+  }
+
+  int a;
+
+  IplImage* _dX = cvCreateImage(cvGetSize(dst), IPL_DEPTH_16S, 1);
+  IplImage* _dY = cvCreateImage(cvGetSize(dst), IPL_DEPTH_16S, 1);
+
+  int aperture_size = 3;
+
+  cvSobel(src, _dX, 1, 0, aperture_size);
+  cvSobel(src, _dY, 0, 1, aperture_size);
+
+  COpencvDataConversion<short, short> ODC1;
+  COpencvDataConversion<uchar, uchar> ODC2;
+  COpencvDataConversion<float, float> ODC3;
+
+  short* dX_data = ODC1.GetImageData(_dX);
+  short* dY_data = ODC1.GetImageData(_dY);
+
+  uchar* dst_u_data = NULL;
+  float* dst_f_data = NULL;
+
+  if (bIsFloat)
+    dst_f_data = ODC3.GetImageData(dst);
+  else
+    dst_u_data = ODC2.GetImageData(dst);
+
+  short* dX = dX_data;
+  short* dY = dY_data;
+  uchar *uSrc = dst_u_data;
+  float *fSrc = dst_f_data;
+
+  /*
+  short* dX = (short*)(_dX->imageData);
+  short* dY = (short*)(_dY->imageData);
+  uchar *dSrc = (uchar*)(dst->imageData);
+  */
+
+  int length;
+  if (src->roi)
+    length = dst->width * dst->height;
+  else
+    length = dst->roi->width * dst->roi->height;
+  /*
+  int x, y;
+  uchar *x_u_data;
+  float *x_f_data;
+  */
+
+  if (bIsFloat) {
+    for (a = 0; a < length; a++) {
+      *fSrc = cvSqrt((float) ((*dX)*(*dX)+(*dY)*(*dY)) / (32.0f * 255.0f));
+      fSrc++;
+      dX++;
+      dY++;
+    }
+    ODC3.SetImageData(dst, dst_f_data);
+    delete [] dst_f_data;
+  } else {
+    for (a = 0; a < length; a++) {
+      *uSrc = cvRound(cvSqrt((float) ((*dX)*(*dX)+(*dY)*(*dY)) / 32.0f));
+      uSrc++;
+      dX++;
+      dY++;
+    }
+    ODC2.SetImageData(dst, dst_u_data);
+    delete [] dst_u_data;
+  }
+
+  delete [] dX_data;
+  delete [] dY_data;
+
+  cvReleaseImage(&_dX);
+  cvReleaseImage(&_dY);
+}
+
+float CMultiLayerBGS::CalVectorsNoisedAngle(float *bg_color, unsigned char *noised_color, float offset, int length) {
+  float org_angle = CalVectorsAngle(bg_color, noised_color, length);
+  float norm_color = 0, elem, noised_angle;
+  int a;
+  for (a = 0; a < length; a++) {
+    elem = bg_color[a];
+    norm_color += elem*elem;
+  }
+  norm_color = sqrtf(norm_color);
+  if (norm_color == 0)
+    noised_angle = PI;
+  else {
+    float sin_angle = offset / norm_color;
+    if (sin_angle < m_fMinNoisedAngleSine)
+      noised_angle = m_fMinNoisedAngle;
+    else
+      //noised_angle = ( sin_angle >= 1 ? PI : asinf(sin_angle));
+      noised_angle = (sin_angle >= 1 ? PI : sin_angle);
+  }
+
+  float angle = org_angle - noised_angle;
+  if (angle < 0)
+    angle = 0;
+  return angle;
+
+  /*
+  float org_angle = CalVectorsAngle(bg_color, noised_color, length);
+  float max_norm_color, bg_norm_color = 0, noised_norm_color = 0, elem, noised_angle;
+  int a;
+  for ( a = 0 ; a <  length ; a++ ) {
+  elem = bg_color[a];
+  bg_norm_color += elem*elem;
+  elem = (float)noised_color[a];
+  noised_norm_color += elem*elem;
+  }
+  max_norm_color = MIN(bg_norm_color, noised_norm_color);
+  max_norm_color = sqrtf(max_norm_color);
+  if ( max_norm_color == 0 )
+  noised_angle = PI;
+  else {
+  float sin_angle = offset/max_norm_color;
+  noised_angle = ( sin_angle >= 1 ? PI : asinf(sin_angle));
+  }
+
+  float angle = org_angle-noised_angle;
+  if ( angle < 0 )
+  angle = 0;
+  return angle;
+  */
+}
+
+float CMultiLayerBGS::CalVectorsAngle(float *c1, unsigned char *c2, int length) {
+  float angle;
+  float dot2, norm1, norm2, elem1, elem2;
+
+  dot2 = norm1 = norm2 = 0;
+
+  int a;
+  for (a = 0; a < length; a++) {
+    elem1 = (float) (c1[a]);
+    elem2 = (float) (c2[a]);
+    dot2 += elem1*elem2;
+    norm1 += elem1*elem1;
+    norm2 += elem2*elem2;
+  }
+
+  //angle = (norm1*norm2==0 ? 0 : acosf(dot2/sqrtf(norm1*norm2)));
+  //angle = (norm1 * norm2 == 0 ? 0 : sqrtf(fmax(1.0f - dot2 * dot2 / (norm1 * norm2), 0.f)));
+  angle = (norm1 * norm2 == 0 ? 0 : sqrtf(std::max(1.0f - dot2 * dot2 / (norm1 * norm2), 0.f)));
+
+  return angle;
+}
+
+float CMultiLayerBGS::CalColorRangeDist(unsigned char *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity, float shadow_rate, float highlight_rate) {
+  float dist = 0.0f, minI, maxI, bgI, curI;
+  int channel;
+  //float cdist;
+
+
+  for (channel = 0; channel < m_nChannel; channel++) {
+    bgI = bg_intensity[channel];
+
+    /*
+    minI = MIN(MIN(min_intensity[channel], bgI*shadow_rate), min_intensity[channel]-15.0f);
+    maxI = MAX(MAX(max_intensity[channel], bgI*highlight_rate), max_intensity[channel]+15.0f);
+    */
+
+    minI = MIN(min_intensity[channel], bgI * shadow_rate - 5.0f);
+    maxI = MAX(max_intensity[channel], bgI * highlight_rate + 5.0f);
+
+    /*
+    if ( rand()/((double)RAND_MAX+1) > 0.999 ) {
+    char msg[200];
+    sprintf(msg, "%d\t%d\n", min_intensity[channel]<bgI*shadow_rate-5.0f ? 1 : 0, max_intensity[channel]>bgI*highlight_rate+5.0f ? 1 : 0);
+    ExportLogMessage(msg);
+    }
+    */
+
+    /*
+    minI = max_intensity[channel]*shadow_rate;
+    maxI = MAX(bg_intensity[channel]+m_fRobustColorOffset, MIN(max_intensity[channel]*highlight_rate,min_intensity[channel]/shadow_rate));
+    */
+
+    curI = (float) (cur_intensity[channel]);
+
+    /*
+    //cdist = fabsf(bgI-curI)/512.0f;
+    if ( curI > bgI )
+    cdist = fabsf(bgI-curI)/256.0f;
+    else
+    cdist = fabsf(bgI-curI)/512.0f;
+
+    if ( curI > maxI )
+    //cdist += (curI-maxI)/(2.0f*(255.0f-maxI))*0.5f;
+    cdist += (1.0f-expf(10.0f*(maxI-curI)/MAX(255.0f-maxI,10.0f)))*0.5f;
+    else if ( curI < minI )
+    //cdist += (minI-curI)/(2.0f*minI)*0.5f;
+    cdist += (1.0f-expf(10.0f*(curI-minI)/MAX(minI,10.0f)))*0.5f;
+    //dist += cdist;
+    if ( cdist > dist )
+    dist = cdist;
+    */
+
+    if (curI > maxI || curI < minI) {
+      dist = 1.0f;
+      break;
+    }
+  }
+  //dist = powf(dist, 1.0f/(float)m_nChannel);
+  //dist /= (float)m_nChannel;
+
+  return dist;
+}
+
+void CMultiLayerBGS::GetLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, CvScalar empty_color) {
+  PixelLBPStruct *PLBP = m_pPixelLBPs;
+  LBPStruct* LBPs;
+  unsigned short* lbp_idxes;
+
+  int a, b, c;
+  int img_length = m_pOrgImg->width * m_pOrgImg->height;
+
+  cvSet(layered_bg_img, empty_color);
+
+  COpencvDataConversion<uchar, uchar> ODC;
+
+  uchar *bg_img_data = ODC.GetImageData(layered_bg_img);
+  uchar *_bg_img_data = bg_img_data;
+  float *cur_bg_intensity;
+  int lbp_num;
+
+  for (a = 0; a < img_length; a++) {
+    // get lbp information
+    LBPs = (*PLBP).LBPs;
+    lbp_idxes = (*PLBP).lbp_idxes;
+    lbp_num = (int) ((*PLBP).num);
+    bool found = false;
+    for (b = 0; b < lbp_num; b++) {
+      if (LBPs[lbp_idxes[b]].bg_layer_num == layered_no) {
+        cur_bg_intensity = LBPs[lbp_idxes[b]].bg_intensity;
+        for (c = 0; c < m_pOrgImg->nChannels; c++)
+          *_bg_img_data++ = (uchar) * cur_bg_intensity++;
+        found = true;
+        break;
+      }
+    }
+    if (!found)
+      _bg_img_data += m_pOrgImg->nChannels;
+
+    PLBP++;
+  }
+
+  ODC.SetImageData(layered_bg_img, bg_img_data);
+
+  delete [] bg_img_data;
+}
+
+void CMultiLayerBGS::GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar *layer_colors, int layer_num) {
+  if (layer_num != 0 && layer_num != m_nMaxLBPModeNum) {
+    printf("Must be set in %d layers in function GetBgLayerNoImage!\n", m_nMaxLBPModeNum);
+    exit(1);
+  }
+
+  CvScalar *bg_layer_colors;
+  int bg_layer_color_num = layer_num;
+  if (bg_layer_color_num == 0)
+    bg_layer_color_num = m_nMaxLBPModeNum;
+  bg_layer_colors = new CvScalar[bg_layer_color_num];
+  if (layer_colors) {
+    for (int l = 0; l < layer_num; l++)
+      bg_layer_colors[l] = layer_colors[l];
+  } else {
+    int rgb[3];
+    rgb[0] = rgb[1] = rgb[2] = 0;
+    int rgb_idx = 0;
+    for (int l = 0; l < bg_layer_color_num; l++) {
+      bg_layer_colors[l] = CV_RGB(rgb[0], rgb[1], rgb[2]);
+      rgb[rgb_idx] += 200;
+      rgb[rgb_idx] %= 255;
+      rgb_idx++;
+      rgb_idx %= 3;
+    }
+  }
+
+  int img_length = m_pOrgImg->width * m_pOrgImg->height;
+  uchar *bg_layer_data = new uchar[img_length * bg_layer_no_img->nChannels];
+  uchar *_bg_layer_data = bg_layer_data;
+
+  PixelLBPStruct *PLBP = m_pPixelLBPs;
+  unsigned int cur_bg_layer_no;
+
+  for (int a = 0; a < img_length; a++) {
+    cur_bg_layer_no = (*PLBP).cur_bg_layer_no;
+    for (int b = 0; b < bg_layer_no_img->nChannels; b++) {
+      *_bg_layer_data++ = (uchar) (bg_layer_colors[cur_bg_layer_no].val[b]);
+    }
+    PLBP++;
+  }
+
+  COpencvDataConversion<uchar, uchar> ODC;
+  ODC.SetImageData(bg_layer_no_img, bg_layer_data);
+
+  delete [] bg_layer_data;
+  delete [] bg_layer_colors;
+}
+
+void CMultiLayerBGS::GetCurrentLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, IplImage *layered_fg_img, CvScalar layered_bg_bk_color, CvScalar layered_fg_color,
+  int smooth_win, float smooth_sigma, float below_layer_noise, float above_layer_noise, int min_blob_size) {
+    PixelLBPStruct *PLBP = m_pPixelLBPs;
+    LBPStruct* LBPs;
+    unsigned short* lbp_idxes;
+
+    int a;
+    int img_length = m_pOrgImg->width * m_pOrgImg->height;
+
+    float *bg_layer_mask = new float[img_length];
+    float *_bg_layer_mask = bg_layer_mask;
+
+    for (a = 0; a < img_length; a++) {
+      // get lbp information
+      LBPs = (*PLBP).LBPs;
+      lbp_idxes = (*PLBP).lbp_idxes;
+      *_bg_layer_mask++ = (float) (*PLBP).cur_bg_layer_no;
+      PLBP++;
+    }
+
+    COpencvDataConversion<float, float> ODC;
+    IplImage* bg_layer_float_mask_img = cvCreateImage(cvGetSize(m_pOrgImg), IPL_DEPTH_32F, 1);
+    IplImage* bg_layer_low_mask_img = cvCreateImage(cvGetSize(m_pOrgImg), IPL_DEPTH_8U, 1);
+    IplImage* bg_layer_high_mask_img = cvCreateImage(cvGetSize(m_pOrgImg), IPL_DEPTH_8U, 1);
+    IplImage* bg_layer_mask_img = cvCreateImage(cvGetSize(m_pOrgImg), IPL_DEPTH_8U, 1);
+
+    ODC.SetImageData(bg_layer_float_mask_img, bg_layer_mask);
+
+    /* method 1 using smooth */
+    /*
+    cvSmooth(bg_layer_float_mask_img, bg_layer_float_mask_img, CV_GAUSSIAN, smooth_win, smooth_win, smooth_sigma);
+
+    cvThreshold(bg_layer_float_mask_img, bg_layer_low_mask_img, (float)layered_no-below_layer_noise, 1, CV_THRESH_BINARY);
+    cvThreshold(bg_layer_float_mask_img, bg_layer_high_mask_img, (float)layered_no+above_layer_noise, 1, CV_THRESH_BINARY_INV);
+
+    cvAnd(bg_layer_low_mask_img, bg_layer_high_mask_img, bg_layer_mask_img);
+    */
+
+    /* method 2 using dilate, erode, blob removing */
+    cvSmooth(bg_layer_float_mask_img, bg_layer_float_mask_img, CV_GAUSSIAN, smooth_win, smooth_win, smooth_sigma);
+
+    cvThreshold(bg_layer_float_mask_img, bg_layer_low_mask_img, (float) layered_no - below_layer_noise, 1, CV_THRESH_BINARY);
+    cvThreshold(bg_layer_float_mask_img, bg_layer_high_mask_img, (float) layered_no + above_layer_noise, 1, CV_THRESH_BINARY_INV);
+    cvAnd(bg_layer_low_mask_img, bg_layer_high_mask_img, bg_layer_mask_img);
+
+    cvDilate(bg_layer_mask_img, bg_layer_mask_img, 0, 2);
+    cvErode(bg_layer_mask_img, bg_layer_mask_img, 0, 2);
+
+    //cvMorphologyEx(bg_layer_mask_img, bg_layer_mask_img, NULL, 0, CV_MOP_OPEN|CV_MOP_CLOSE, 1);
+
+    // Extract the blobs using a threshold of 100 in the image
+    CBlobResult blobs = CBlobResult(bg_layer_mask_img, NULL, 0, true);
+    // discard the blobs with less area than 100 pixels
+    // ( the criteria to filter can be any class derived from COperadorBlob )
+    blobs.Filter(blobs, B_INCLUDE, CBlobGetArea(), B_GREATER, min_blob_size);
+
+    CBlob filtered_blob;
+    cvSetZero(bg_layer_mask_img);
+    for (a = 0; a < blobs.GetNumBlobs(); a++) {
+      filtered_blob = blobs.GetBlob(a);
+      filtered_blob.FillBlob(bg_layer_mask_img, cvScalar(1));
+    }
+    blobs.GetNthBlob(CBlobGetArea(), 0, filtered_blob);
+    filtered_blob.FillBlob(bg_layer_mask_img, cvScalar(0));
+
+
+    cvSet(layered_bg_img, layered_bg_bk_color);
+    cvCopy(m_pBgImg, layered_bg_img, bg_layer_mask_img);
+
+    if (layered_fg_img) {
+      cvCopy(m_pOrgImg, layered_fg_img);
+      cvSet(layered_fg_img, layered_fg_color, bg_layer_mask_img);
+    }
+
+    cvReleaseImage(&bg_layer_float_mask_img);
+    cvReleaseImage(&bg_layer_low_mask_img);
+    cvReleaseImage(&bg_layer_high_mask_img);
+    cvReleaseImage(&bg_layer_mask_img);
+    delete [] bg_layer_mask;
+}
+
+void CMultiLayerBGS::GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors) {
+  cvCopyImage(m_pOrgImg, bg_multi_layer_img);
+
+  COpencvDataConversion<uchar, uchar> ODC;
+
+  uchar *bg_ml_imgD = ODC.GetImageData(bg_multi_layer_img);
+  uchar *fg_maskD = ODC.GetImageData(m_pFgMaskImg);
+
+  uchar *_bg_ml_imgD = bg_ml_imgD;
+  uchar *_fg_maskD = fg_maskD;
+
+  PixelLBPStruct *PLBP = m_pPixelLBPs;
+  LBPStruct* LBPs;
+  unsigned short* lbp_idxes;
+  unsigned int lbp_num;
+  int bg_layer_num;
+
+  int a, c;
+  int img_length = m_pOrgImg->width * m_pOrgImg->height;
+  int channels = m_pOrgImg->nChannels;
+  bool bLayeredBg;
+
+  for (a = 0; a < img_length; a++) {
+    // get lbp information
+    lbp_num = (*PLBP).num;
+    LBPs = (*PLBP).LBPs;
+    lbp_idxes = (*PLBP).lbp_idxes;
+    bLayeredBg = false;
+
+    if ((*_fg_maskD == 0)) {
+      bg_layer_num = LBPs[lbp_idxes[0]].bg_layer_num;
+      int first_layer_idx = 0;
+      for (c = 0; c < (int) lbp_num; c++) {
+        if (LBPs[lbp_idxes[c]].bg_layer_num == 1) {
+          first_layer_idx = c;
+          break;
+        }
+      }
+      if (bg_layer_num > 1 && DistLBP(&(LBPs[lbp_idxes[0]]), &(LBPs[first_layer_idx])) > 0.1f) {
+        for (c = 0; c < channels; c++)
+          *_bg_ml_imgD++ = (uchar) (layer_colors[bg_layer_num].val[c]);
+        bLayeredBg = true;
+      }
+
+      if (!bLayeredBg)
+        _bg_ml_imgD += channels;
+    } else {
+      _bg_ml_imgD += channels;
+    }
+
+    PLBP++;
+    _fg_maskD++;
+  }
+
+  ODC.SetImageData(bg_multi_layer_img, bg_ml_imgD);
+
+  delete [] fg_maskD;
+  delete [] bg_ml_imgD;
+}
+
+void CMultiLayerBGS::GetForegroundProbabilityImage(IplImage *fg_dist_img) {
+  COpencvDataConversion<float, float> ODC1;
+  COpencvDataConversion<uchar, uchar> ODC2;
+
+  float *_fg_distD = ODC1.GetImageData(m_pBgDistImg);
+  uchar *_fg_progI = ODC2.GetImageData(fg_dist_img);
+  float *fg_distD = _fg_distD;
+  uchar *fg_progI = _fg_progI;
+
+  /*
+  float *fg_distD = (float*)(m_pBgDistImg->imageData);
+  uchar *fg_progI = (uchar*)(fg_dist_img->imageData);
+  */
+
+  int channels = fg_dist_img->nChannels;
+
+  int a, b;
+  int img_length = fg_dist_img->width * fg_dist_img->height;
+  uchar temp;
+  for (a = 0; a < img_length; a++) {
+    temp = cvRound(255.0f * ((*fg_distD++)));
+    for (b = 0; b < channels; b++)
+      *fg_progI++ = temp;
+  }
+
+  ODC2.SetImageData(fg_dist_img, _fg_progI);
+
+  delete [] _fg_distD;
+  delete [] _fg_progI;
+}
+
+void CMultiLayerBGS::RemoveBackgroundLayers(PixelLBPStruct *PLBP, bool *removed_modes) {
+  int a, b;
+  int lbp_num = PLBP->num;
+
+  /*
+  if ( lbp_num < m_nMaxLBPModeNum )
+  return;
+  */
+
+  /* testing */
+
+  unsigned short* lbp_idxes = PLBP->lbp_idxes;
+  if (!removed_modes) {
+    int removed_bg_layer_num = 0;
+    for (a = 0; a < lbp_num; a++) {
+      if (PLBP->LBPs[lbp_idxes[a]].bg_layer_num && PLBP->LBPs[lbp_idxes[a]].weight < m_fMinBgLayerWeight) { // should be removed
+        removed_bg_layer_num = PLBP->LBPs[lbp_idxes[a]].bg_layer_num;
+        lbp_num--;
+        for (b = a; b < lbp_num; b++)
+          lbp_idxes[b] = lbp_idxes[b + 1];
+        break;
+      }
+    }
+    if (removed_bg_layer_num) {
+      for (a = 0; a < lbp_num; a++) {
+        if (PLBP->LBPs[lbp_idxes[a]].bg_layer_num > removed_bg_layer_num)
+          PLBP->LBPs[lbp_idxes[a]].bg_layer_num--;
+      }
+    }
+  } else {
+    int removed_bg_layer_nums[10];
+    int removed_layer_num = 0;
+    for (a = 0; a < lbp_num; a++) {
+      if (removed_modes[a] && PLBP->LBPs[lbp_idxes[a]].bg_layer_num) { // should be removed
+        removed_bg_layer_nums[removed_layer_num++] = PLBP->LBPs[lbp_idxes[a]].bg_layer_num;
+      }
+    }
+
+    for (a = 0; a < lbp_num; a++) {
+      if (removed_modes[a]) { // should be removed
+        lbp_num--;
+        for (b = a; b < lbp_num; b++)
+          lbp_idxes[b] = lbp_idxes[b + 1];
+      }
+    }
+
+    for (a = 0; a < lbp_num; a++) {
+      for (b = 0; b < removed_layer_num; b++) {
+        if (PLBP->LBPs[lbp_idxes[a]].bg_layer_num > removed_bg_layer_nums[b])
+          PLBP->LBPs[lbp_idxes[a]].bg_layer_num--;
+      }
+    }
+  }
+
+  // sort the list of modes based on the weights of modes
+  if (lbp_num != (int) PLBP->num) {
+    float weights[100], tot_weights = 0;
+    for (a = 0; a < (int) lbp_num; a++) {
+      weights[a] = PLBP->LBPs[lbp_idxes[a]].weight;
+      tot_weights += weights[a];
+    }
+
+    // sort weights in the descent order
+    QuickSort(weights, lbp_idxes, 0, (int) lbp_num - 1, false);
+
+    // calculate the first potential background modes number, bg_num
+    float threshold_weight = m_fBackgroundModelPercent*tot_weights;
+    int bg_num = 0;
+    tot_weights = 0;
+    for (a = 0; a < (int) lbp_num; a++) {
+      tot_weights += PLBP->LBPs[lbp_idxes[a]].weight;
+      if (tot_weights > threshold_weight) {
+        bg_num = a + 1;
+        break;
+      }
+    }
+    (*PLBP).bg_num = bg_num;
+
+  }
+
+  PLBP->num = lbp_num;
+
+  float bg_layer_data[10];
+  unsigned short bg_layer_idxes[10];
+  int bg_layer_num;
+  int tot_bg_layer_num = 0;
+  for (a = 0; a < lbp_num; a++) {
+    bg_layer_num = PLBP->LBPs[lbp_idxes[a]].bg_layer_num;
+    if (bg_layer_num) {
+      bg_layer_data[tot_bg_layer_num] = (float) bg_layer_num;
+      bg_layer_idxes[tot_bg_layer_num++] = lbp_idxes[a];
+    }
+  }
+  if (tot_bg_layer_num == 1) {
+    PLBP->LBPs[bg_layer_idxes[0]].bg_layer_num = 1;
+  } else if (tot_bg_layer_num) {
+    // sort weights in the descent order
+    QuickSort(bg_layer_data, bg_layer_idxes, 0, tot_bg_layer_num - 1, true);
+    for (a = 0; a < tot_bg_layer_num; a++)
+      PLBP->LBPs[bg_layer_idxes[a]].bg_layer_num = a + 1;
+  }
+
+  /*
+  int max_bg_layer_num = 0;
+  for ( a = 0 ; a < lbp_num ; a++ )
+  max_bg_layer_num = MAX(max_bg_layer_num, PLBP->LBPs[lbp_idxes[a]].bg_layer_num);
+  if ( max_bg_layer_num >= 2 ) {
+  bool find_first_layer = false;
+  for ( a = 0 ; a < lbp_num ; a++ ) {
+  max_bg_layer_num = MAX(max_bg_layer_num, PLBP->LBPs[lbp_idxes[a]].bg_layer_num);
+  if ( PLBP->LBPs[lbp_idxes[a]].bg_layer_num == 1 ) {
+  find_first_layer = true;
+  break;
+  }
+  }
+  if ( !find_first_layer ) {
+  printf("\n===============================================\n");
+  printf(" have second layer, no first layer \n");
+  printf("\n===============================================\n");
+  exit(1);
+  }
+  }
+  */
+}
+
+void CMultiLayerBGS::Postprocessing() {
+  // post-processing for background subtraction results
+  cvDilate(m_pFgMaskImg, m_pFgMaskImg, 0, 2);
+  cvErode(m_pFgMaskImg, m_pFgMaskImg, 0, 2);
+
+  /** Example of extracting and filtering the blobs of an image */
+
+  // object that will contain blobs of inputImage
+  CBlobResult blobs;
+
+  IplImage *inputImage = m_pFgMaskImg;
+
+  // Extract the blobs using a threshold of 100 in the image
+  blobs = CBlobResult(inputImage, NULL, 0, true);
+
+  // create a file with some of the extracted features
+  //blobs.PrintBlobs( ".\\blobs.txt" );
+
+  // discard the blobs with less area than 100 pixels
+  // ( the criteria to filter can be any class derived from COperadorBlob )
+  blobs.Filter(blobs, B_INCLUDE, CBlobGetArea(), B_GREATER, 100);
+
+  // create a file with filtered results
+  //blobs.PrintBlobs( ".\\filteredBlobs.txt" );
+
+  // build an output image equal to the input but with 3 channels (to draw the coloured blobs)
+  IplImage *outputImage;
+  outputImage = cvCreateImage(cvSize(inputImage->width, inputImage->height), IPL_DEPTH_8U, 1);
+  cvSet(outputImage, cvScalar(0));
+
+  // plot the selected blobs in a output image
+  CBlob filtered_blob;
+  //cvSet(outputImage, CV_RGB(0,0,255));
+  int a;
+  for (a = 0; a < blobs.GetNumBlobs(); a++) {
+    filtered_blob = blobs.GetBlob(a);
+    filtered_blob.FillBlob(outputImage, cvScalar(255));
+  }
+  blobs.GetNthBlob(CBlobGetArea(), 0, filtered_blob);
+  filtered_blob.FillBlob(outputImage, cvScalar(0));
+
+  /*
+  char *win_name = "blob filtered image";
+  cvNamedWindow(win_name);
+  cvShowImage(win_name, outputImage);
+  cvWaitKey(3);
+  */
+
+  cvReleaseImage(&outputImage);
+}
+
+void CMultiLayerBGS::GetFloatEdgeImage(IplImage *src, IplImage *dst) {
+  if (src->nChannels > 1) {
+    printf("Error: the input source image must be single-channel image!\n");
+    exit(1);
+  }
+  if (dst->depth != IPL_DEPTH_32F) {
+    printf("Error: the output edge image must be float image ranging in [0,1]!\n");
+    exit(1);
+  }
+
+  uchar *src_x_data;
+  float *dst_x_data;
+
+  int x, y;
+  for (y = 0; y < dst->height; y++) {
+    src_x_data = (uchar*) (src->imageData + src->widthStep * y);
+    dst_x_data = (float*) (dst->imageData + dst->widthStep * y);
+    for (x = 0; x < dst->width; x++) {
+      *dst_x_data++ = (float) (*src_x_data++) / 255.0f;
+    }
+  }
+}
+
+void CMultiLayerBGS::ExportLogMessage(char *msg) {
+  const char *log_fn = "log_message.txt";
+  ofstream fout(log_fn, ios::app);
+  if (fout.fail()) {
+    printf("Error opening log output file %s.\n", log_fn);
+    fout.close();
+    exit(0);
+  }
+
+  fout << msg;
+  fout.close();
+}
+
+void CMultiLayerBGS::UpdatePatternColorDistWeights(float *cur_pattern, float *bg_pattern) {
+  return;
+
+  int cur_true_num = 0, cur_false_num = 0, bg_true_num = 0, bg_false_num = 0;
+  int a;
+
+  for (a = 0; a < m_nLBPLength; a++) {
+    cur_true_num += (cur_pattern[a] > 0.5f ? 1 : 0);
+    cur_false_num += (cur_pattern[a] < 0.5f ? 0 : 1);
+    bg_true_num += (bg_pattern[a] > 0.5f);
+    bg_false_num += (bg_pattern[a] < 0.5f);
+  }
+  m_fTextureWeight = expf(-(fabsf(cur_true_num - cur_false_num) + fabsf(bg_true_num - bg_false_num) + 0.8f) / (float) m_nLBPLength);
+  m_fTextureWeight = MAX(MIN(m_fTextureWeight, 0.5f), 0.1f);
+  m_fColorWeight = 1.0f - m_fTextureWeight;
+}
+
+void CMultiLayerBGS::Save(const char *bg_model_fn) {
+  Save(bg_model_fn, 2);
+}
+
+void CMultiLayerBGS::Save(const char *bg_model_fn, int save_type) {
+  FILE * fout = fopen(bg_model_fn, "w");
+  if (!fout) {
+    printf("Error opening background model output file %s.\n", bg_model_fn);
+    fclose(fout);
+    //exit(0);
+    return;
+  }
+
+  int i, j;
+  if (save_type == 0) { /* save the background model information */
+    fprintf(fout, "FILE_TYPE:  MODEL_INFO\n\n");
+
+    fprintf(fout, "MAX_MODEL_NUM: %5d\n", m_nMaxLBPModeNum);
+    fprintf(fout, "LBP_LENGTH: %5d\n", m_nLBPLength);
+    fprintf(fout, "CHANNELS_NUM: %5d\n", m_nChannel);
+    fprintf(fout, "IMAGE_SIZE: %5d %5d\n\n", m_cvImgSize.width, m_cvImgSize.height);
+
+    fprintf(fout, "MODEL_INFO_PIXEL_BY_PIXEL:\n");
+
+    int img_length = m_cvImgSize.height * m_cvImgSize.width;
+    PixelLBPStruct* PLBP = m_pPixelLBPs;
+
+    for (int yx = 0; yx < img_length; yx++) {
+      fprintf(fout, "%3d %3d %3d", (*PLBP).num, (*PLBP).bg_num, (*PLBP).cur_bg_layer_no);
+      for (i = 0; i < (int) (*PLBP).num; i++)
+        fprintf(fout, " %3d", (*PLBP).lbp_idxes[i]);
+      for (i = 0; i < (int) (*PLBP).num; i++) {
+        int li = (*PLBP).lbp_idxes[i];
+        for (j = 0; j < m_nChannel; j++) {
+          fprintf(fout, " %7.1f %7.1f %7.1f", (*PLBP).LBPs[li].bg_intensity[j],
+            (*PLBP).LBPs[li].max_intensity[j], (*PLBP).LBPs[li].min_intensity[j]);
+        }
+        for (j = 0; j < m_nLBPLength; j++)
+          fprintf(fout, " %7.3f", (*PLBP).LBPs[li].bg_pattern[j]);
+        fprintf(fout, " %10.5f", (*PLBP).LBPs[li].weight);
+        fprintf(fout, " %10.5f", (*PLBP).LBPs[li].max_weight);
+        fprintf(fout, " %3d", (*PLBP).LBPs[li].bg_layer_num);
+        fprintf(fout, " %20lu", (*PLBP).LBPs[li].first_time);
+        fprintf(fout, " %20lu", (*PLBP).LBPs[li].last_time);
+        fprintf(fout, " %8d", (*PLBP).LBPs[li].freq);
+      }
+      fprintf(fout, "\n");
+      PLBP++;
+    }
+  } else if (save_type == 1) { /* save current parameters for background subtraction */
+    fprintf(fout, "FILE_TYPE:  MODEL_PARAS\n\n");
+
+    fprintf(fout, "MAX_MODEL_NUM: %5d\n", m_nMaxLBPModeNum);
+    fprintf(fout, "FRAME_DURATION: %f\n", m_fFrameDuration);
+    fprintf(fout, "MODEL_UPDATING_LEARN_RATE: %f\n", m_fModeUpdatingLearnRate);
+    fprintf(fout, "WEIGHT_UPDATING_LEARN_RATE: %f\n", m_fWeightUpdatingLearnRate);
+    fprintf(fout, "WEIGHT_UPDATING_CONSTANT: %f\n", m_fWeightUpdatingConstant);
+    fprintf(fout, "LOW_INITIAL_MODE_WEIGHT: %f\n", m_fLowInitialModeWeight);
+    fprintf(fout, "RELIABLE_BACKGROUND_MODE_WEIGHT: %f\n", m_fReliableBackgroundModeWeight);
+    fprintf(fout, "ROBUST_COLOR_OFFSET: %f\n", m_fRobustColorOffset);
+    fprintf(fout, "BACKGROUND_MODEL_PERCENT: %f\n", m_fBackgroundModelPercent);
+    fprintf(fout, "ROBUST_SHADOW_RATE: %f\n", m_fRobustShadowRate);
+    fprintf(fout, "ROBUST_HIGHLIGHT_RATE: %f\n", m_fRobustHighlightRate);
+    fprintf(fout, "PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD: %f\n", m_fPatternColorDistBgThreshold);
+    fprintf(fout, "PATTERN_COLOR_DIST_BACKGROUND_UPDATED_THRESHOLD: %f\n", m_fPatternColorDistBgUpdatedThreshold);
+    fprintf(fout, "MIN_BACKGROUND_LAYER_WEIGHT: %f\n", m_fMinBgLayerWeight);
+    fprintf(fout, "PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE: %d\n", m_nPatternDistSmoothNeigHalfSize);
+    fprintf(fout, "PATTERN_DIST_CONV_GAUSSIAN_SIGMA: %f\n", m_fPatternDistConvGaussianSigma);
+    fprintf(fout, "TEXTURE_WEIGHT: %f\n", m_fTextureWeight);
+    fprintf(fout, "MIN_NOISED_ANGLE: %f\n", m_fMinNoisedAngle);
+    fprintf(fout, "MIN_NOISED_ANGLE_SINE: %f\n", m_fMinNoisedAngleSine);
+    fprintf(fout, "BILATERAL_SIGMA_S: %f\n", m_fSigmaS);
+    fprintf(fout, "BILATERAL_SIGMA_R: %f\n", m_fSigmaR);
+    fprintf(fout, "LBP_LENGTH: %5d\n", m_nLBPLength);
+    fprintf(fout, "LBP_LEVEL_NUM: %5d\n", m_nLBPLevelNum);
+    fprintf(fout, "LBP_RADIUSES: ");
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fprintf(fout, "%10.5f", m_pLBPRadiuses[i]);
+    fprintf(fout, "\nLBP_NEIG_POINT_NUMS: ");
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fprintf(fout, "%6d", m_pLBPMeigPointNums[i]);
+  } else if (save_type == 2) { /* save the background model information and parameters */
+    fprintf(fout, "FILE_TYPE:  MODEL_PARAS_INFO\n\n");
+
+    fprintf(fout, "MAX_MODEL_NUM: %5d\n", m_nMaxLBPModeNum);
+    fprintf(fout, "FRAME_DURATION: %f\n", m_fFrameDuration);
+    fprintf(fout, "MODEL_UPDATING_LEARN_RATE: %f\n", m_fModeUpdatingLearnRate);
+    fprintf(fout, "WEIGHT_UPDATING_LEARN_RATE: %f\n", m_fWeightUpdatingLearnRate);
+    fprintf(fout, "WEIGHT_UPDATING_CONSTANT: %f\n", m_fWeightUpdatingConstant);
+    fprintf(fout, "LOW_INITIAL_MODE_WEIGHT: %f\n", m_fLowInitialModeWeight);
+    fprintf(fout, "RELIABLE_BACKGROUND_MODE_WEIGHT: %f\n", m_fReliableBackgroundModeWeight);
+    fprintf(fout, "ROBUST_COLOR_OFFSET: %f\n", m_fRobustColorOffset);
+    fprintf(fout, "BACKGROUND_MODEL_PERCENT: %f\n", m_fBackgroundModelPercent);
+    fprintf(fout, "ROBUST_SHADOW_RATE: %f\n", m_fRobustShadowRate);
+    fprintf(fout, "ROBUST_HIGHLIGHT_RATE: %f\n", m_fRobustHighlightRate);
+    fprintf(fout, "PATTERN_COLOR_DIST_BACKGROUND_THRESHOLD: %f\n", m_fPatternColorDistBgThreshold);
+    fprintf(fout, "PATTERN_COLOR_DIST_BACKGROUND_UPDATED_THRESHOLD: %f\n", m_fPatternColorDistBgUpdatedThreshold);
+    fprintf(fout, "MIN_BACKGROUND_LAYER_WEIGHT: %f\n", m_fMinBgLayerWeight);
+    fprintf(fout, "PATTERN_DIST_SMOOTH_NEIG_HALF_SIZE: %d\n", m_nPatternDistSmoothNeigHalfSize);
+    fprintf(fout, "PATTERN_DIST_CONV_GAUSSIAN_SIGMA: %f\n", m_fPatternDistConvGaussianSigma);
+    fprintf(fout, "TEXTURE_WEIGHT: %f\n", m_fTextureWeight);
+    fprintf(fout, "MIN_NOISED_ANGLE: %f\n", m_fMinNoisedAngle);
+    fprintf(fout, "MIN_NOISED_ANGLE_SINE: %f\n", m_fMinNoisedAngleSine);
+    fprintf(fout, "BILATERAL_SIGMA_S: %f\n", m_fSigmaS);
+    fprintf(fout, "BILATERAL_SIGMA_R: %f\n", m_fSigmaR);
+    fprintf(fout, "LBP_LENGTH: %5d\n", m_nLBPLength);
+    fprintf(fout, "LBP_LEVEL_NUM: %5d\n", m_nLBPLevelNum);
+    fprintf(fout, "LBP_RADIUSES: ");
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fprintf(fout, "%10.5f", m_pLBPRadiuses[i]);
+    fprintf(fout, "\nLBP_NEIG_POINT_NUMS: ");
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fprintf(fout, "%6d", m_pLBPMeigPointNums[i]);
+
+    fprintf(fout, "\nMAX_MODEL_NUM: %5d\n", m_nMaxLBPModeNum);
+    fprintf(fout, "LBP_LENGTH: %5d\n", m_nLBPLength);
+    fprintf(fout, "CHANNELS_NUM: %5d\n", m_nChannel);
+    fprintf(fout, "IMAGE_SIZE: %5d %5d\n\n", m_cvImgSize.width, m_cvImgSize.height);
+
+    fprintf(fout, "MODEL_INFO_PIXEL_BY_PIXEL:\n");
+
+    int img_length = m_cvImgSize.height * m_cvImgSize.width;
+    PixelLBPStruct* PLBP = m_pPixelLBPs;
+
+    for (int yx = 0; yx < img_length; yx++) {
+      fprintf(fout, "%3d %3d %3d", (*PLBP).num, (*PLBP).bg_num, (*PLBP).cur_bg_layer_no);
+      for (i = 0; i < (int) (*PLBP).num; i++)
+        fprintf(fout, " %3d", (*PLBP).lbp_idxes[i]);
+      for (i = 0; i < (int) (*PLBP).num; i++) {
+        int li = (*PLBP).lbp_idxes[i];
+        for (j = 0; j < m_nChannel; j++) {
+          fprintf(fout, " %7.1f %7.1f %7.1f", (*PLBP).LBPs[li].bg_intensity[j],
+            (*PLBP).LBPs[li].max_intensity[j], (*PLBP).LBPs[li].min_intensity[j]);
+        }
+        for (j = 0; j < m_nLBPLength; j++)
+          fprintf(fout, " %7.3f", (*PLBP).LBPs[li].bg_pattern[j]);
+        fprintf(fout, " %10.5f", (*PLBP).LBPs[li].weight);
+        fprintf(fout, " %10.5f", (*PLBP).LBPs[li].max_weight);
+        fprintf(fout, " %3d", (*PLBP).LBPs[li].bg_layer_num);
+        fprintf(fout, " %20lu", (*PLBP).LBPs[li].first_time);
+        fprintf(fout, " %20lu", (*PLBP).LBPs[li].last_time);
+        fprintf(fout, " %8d", (*PLBP).LBPs[li].freq);
+      }
+      fprintf(fout, "\n");
+      PLBP++;
+    }
+  } else { /* wrong save type */
+    printf("Please input correct save type: 0 - model_info  1 - model_paras  2 - model_paras_info\n");
+    fclose(fout);
+    exit(0);
+  }
+
+  fclose(fout);
+}
+
+bool CMultiLayerBGS::Load(const char *bg_model_fn) {
+  ifstream fin(bg_model_fn, ios::in);
+  if (fin.fail()) {
+    printf("Error opening background model file %s.\n", bg_model_fn);
+    fin.close();
+    return false;
+  }
+
+  char para_name[1024], model_type[1024];
+
+  fin >> para_name >> model_type;
+
+  int i, j;
+  CvSize img_size;
+  int img_length = m_cvImgSize.width * m_cvImgSize.height;
+  int max_lbp_mode_num = m_nMaxLBPModeNum;
+
+  if (!strcmp(model_type, "MODEL_INFO")) {
+    fin >> para_name >> m_nMaxLBPModeNum;
+    fin >> para_name >> m_nLBPLength;
+    fin >> para_name >> m_nChannel;
+    fin >> para_name >> img_size.width >> img_size.height;
+
+    if (m_cvImgSize.width != img_size.width || m_cvImgSize.height != img_size.height) {
+      printf("Image size is not matched!\n");
+      return false;
+    }
+
+    if (max_lbp_mode_num != m_nMaxLBPModeNum) {
+      PixelLBPStruct* PLBP = m_pPixelLBPs;
+      for (int yx = 0; yx < img_length; yx++) {
+        delete [] (*PLBP).LBPs;
+        delete [] (*PLBP).lbp_idxes;
+        (*PLBP).LBPs = new LBPStruct[m_nMaxLBPModeNum];
+        (*PLBP).lbp_idxes = new unsigned short[m_nMaxLBPModeNum];
+      }
+    }
+
+    fin >> para_name;
+
+    int img_length = m_cvImgSize.height * m_cvImgSize.width;
+    PixelLBPStruct* PLBP = m_pPixelLBPs;
+
+    for (int yx = 0; yx < img_length; yx++) {
+      fin >> (*PLBP).num >> (*PLBP).bg_num >> (*PLBP).cur_bg_layer_no;
+      for (i = 0; i < (int) (*PLBP).num; i++)
+        fin >> (*PLBP).lbp_idxes[i];
+      for (i = 0; i < (int) (*PLBP).num; i++) {
+        int li = (*PLBP).lbp_idxes[i];
+        for (j = 0; j < m_nChannel; j++) {
+          fin >> (*PLBP).LBPs[li].bg_intensity[j] >>
+            (*PLBP).LBPs[li].max_intensity[j] >> (*PLBP).LBPs[li].min_intensity[j];
+        }
+        for (j = 0; j < m_nLBPLength; j++)
+          fin >> (*PLBP).LBPs[li].bg_pattern[j];
+        fin >> (*PLBP).LBPs[li].weight >> (*PLBP).LBPs[li].max_weight >> (*PLBP).LBPs[li].bg_layer_num
+          >> (*PLBP).LBPs[li].first_time >> (*PLBP).LBPs[li].last_time >> (*PLBP).LBPs[li].freq;
+      }
+      PLBP++;
+    }
+  } else if (!strcmp(model_type, "MODEL_PARAS")) {
+    fin >> para_name >> m_nMaxLBPModeNum;
+    fin >> para_name >> m_fFrameDuration;
+    fin >> para_name >> m_fModeUpdatingLearnRate;
+    fin >> para_name >> m_fWeightUpdatingLearnRate;
+    fin >> para_name >> m_fWeightUpdatingConstant;
+    fin >> para_name >> m_fLowInitialModeWeight;
+    fin >> para_name >> m_fReliableBackgroundModeWeight;
+    fin >> para_name >> m_fRobustColorOffset;
+    fin >> para_name >> m_fBackgroundModelPercent;
+    fin >> para_name >> m_fRobustShadowRate;
+    fin >> para_name >> m_fRobustHighlightRate;
+    fin >> para_name >> m_fPatternColorDistBgThreshold;
+    fin >> para_name >> m_fPatternColorDistBgUpdatedThreshold;
+    fin >> para_name >> m_fMinBgLayerWeight;
+    fin >> para_name >> m_nPatternDistSmoothNeigHalfSize;
+    fin >> para_name >> m_fPatternDistConvGaussianSigma;
+    fin >> para_name >> m_fTextureWeight;
+    fin >> para_name >> m_fMinNoisedAngle;
+    fin >> para_name >> m_fMinNoisedAngleSine;
+    fin >> para_name >> m_fSigmaS;
+    fin >> para_name >> m_fSigmaR;
+    fin >> para_name >> m_nLBPLength;
+    fin >> para_name >> m_nLBPLevelNum;
+    fin >> para_name;
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fin >> m_pLBPRadiuses[i];
+    fin >> para_name;
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fin >> m_pLBPMeigPointNums[i];
+  } else if (!strcmp(model_type, "MODEL_PARAS_INFO")) {
+    fin >> para_name >> m_nMaxLBPModeNum;
+    fin >> para_name >> m_fFrameDuration;
+    fin >> para_name >> m_fModeUpdatingLearnRate;
+    fin >> para_name >> m_fWeightUpdatingLearnRate;
+    fin >> para_name >> m_fWeightUpdatingConstant;
+    fin >> para_name >> m_fLowInitialModeWeight;
+    fin >> para_name >> m_fReliableBackgroundModeWeight;
+    fin >> para_name >> m_fRobustColorOffset;
+    fin >> para_name >> m_fBackgroundModelPercent;
+    fin >> para_name >> m_fRobustShadowRate;
+    fin >> para_name >> m_fRobustHighlightRate;
+    fin >> para_name >> m_fPatternColorDistBgThreshold;
+    fin >> para_name >> m_fPatternColorDistBgUpdatedThreshold;
+    fin >> para_name >> m_fMinBgLayerWeight;
+    fin >> para_name >> m_nPatternDistSmoothNeigHalfSize;
+    fin >> para_name >> m_fPatternDistConvGaussianSigma;
+    fin >> para_name >> m_fTextureWeight;
+    fin >> para_name >> m_fMinNoisedAngle;
+    fin >> para_name >> m_fMinNoisedAngleSine;
+    fin >> para_name >> m_fSigmaS;
+    fin >> para_name >> m_fSigmaR;
+    fin >> para_name >> m_nLBPLength;
+    fin >> para_name >> m_nLBPLevelNum;
+    fin >> para_name;
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fin >> m_pLBPRadiuses[i];
+    fin >> para_name;
+    for (i = 0; i < m_nLBPLevelNum; i++)
+      fin >> m_pLBPMeigPointNums[i];
+
+    fin >> para_name >> m_nMaxLBPModeNum;
+    fin >> para_name >> m_nLBPLength;
+    fin >> para_name >> m_nChannel;
+    fin >> para_name >> img_size.width >> img_size.height;
+
+    if (m_cvImgSize.width != img_size.width || m_cvImgSize.height != img_size.height) {
+      printf("Image size is not matched!\n");
+      return false;
+    }
+
+    if (max_lbp_mode_num != m_nMaxLBPModeNum) {
+      PixelLBPStruct* PLBP = m_pPixelLBPs;
+      for (int yx = 0; yx < img_length; yx++) {
+        delete [] (*PLBP).LBPs;
+        delete [] (*PLBP).lbp_idxes;
+        (*PLBP).LBPs = new LBPStruct[m_nMaxLBPModeNum];
+        (*PLBP).lbp_idxes = new unsigned short[m_nMaxLBPModeNum];
+      }
+    }
+
+    fin >> para_name;
+
+    int img_length = m_cvImgSize.height * m_cvImgSize.width;
+    PixelLBPStruct* PLBP = m_pPixelLBPs;
+
+    for (int yx = 0; yx < img_length; yx++) {
+      fin >> (*PLBP).num >> (*PLBP).bg_num >> (*PLBP).cur_bg_layer_no;
+      for (i = 0; i < (int) (*PLBP).num; i++)
+        fin >> (*PLBP).lbp_idxes[i];
+      for (i = 0; i < (int) (*PLBP).num; i++) {
+        int li = (*PLBP).lbp_idxes[i];
+        for (j = 0; j < m_nChannel; j++) {
+          fin >> (*PLBP).LBPs[li].bg_intensity[j] >>
+            (*PLBP).LBPs[li].max_intensity[j] >> (*PLBP).LBPs[li].min_intensity[j];
+        }
+        for (j = 0; j < m_nLBPLength; j++)
+          fin >> (*PLBP).LBPs[li].bg_pattern[j];
+        fin >> (*PLBP).LBPs[li].weight >> (*PLBP).LBPs[li].max_weight >> (*PLBP).LBPs[li].bg_layer_num
+          >> (*PLBP).LBPs[li].first_time >> (*PLBP).LBPs[li].last_time >> (*PLBP).LBPs[li].freq;
+      }
+      PLBP++;
+    }
+  } else {
+    printf("Not correct model save type!\n");
+    fin.close();
+    exit(0);
+  }
+
+  fin.close();
+
+  ResetAllParameters();
+
+  return true;
+}
+
+void CMultiLayerBGS::SetValidPointMask(IplImage *maskImage, int mode) {
+  if (mode == 1)
+    SetBkMaskImage(maskImage);
+  else
+    cvAnd(m_pBkMaskImg, maskImage, m_pBkMaskImg);
+}
+
+void CMultiLayerBGS::SetFrameRate(float frameDuration) {
+  m_fModeUpdatingLearnRate = m_fModeUpdatingLearnRatePerSecond*frameDuration;
+  m_fWeightUpdatingLearnRate = m_fWeightUpdatingLearnRatePerSecond*frameDuration;
+
+  m_fFrameDuration = frameDuration;
+
+  m_f1_ModeUpdatingLearnRate = 1.0f - m_fModeUpdatingLearnRate;
+  m_f1_WeightUpdatingLearnRate = 1.0f - m_fWeightUpdatingLearnRate;
+}
+
+void CMultiLayerBGS::Init(int width, int height) {
+  IplImage* first_img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
+  int lbp_level_num = 1;
+  float radiuses[] = {2.0f};
+  int neig_pt_nums[] = {6};
+  Initialization(first_img, lbp_level_num, radiuses, neig_pt_nums);
+  cvReleaseImage(&first_img);
+}
+
+int CMultiLayerBGS::SetRGBInputImage(IplImage *inputImage, CvRect *roi) {
+  if (!inputImage) {
+    printf("Please allocate the IplImage memory!\n");
+    return 0;
+  }
+  if (inputImage->width != m_cvImgSize.width ||
+    inputImage->height != m_cvImgSize.height ||
+    inputImage->depth != IPL_DEPTH_8U ||
+    inputImage->nChannels != 3) {
+      printf("Please provide the correct IplImage pointer, \ne.g. inputImage = cvCreateImage(imgSize, IPL_DEPTH_8U, 3);\n");
+      return 0;
+  }
+  SetNewImage(inputImage, roi);
+  return 1;
+}
+
+void CMultiLayerBGS::SetParameters(int max_lbp_mode_num, float mode_updating_learn_rate_per_second, float weight_updating_learn_rate_per_second, float low_init_mode_weight) {
+  m_nMaxLBPModeNum = max_lbp_mode_num;
+  m_fModeUpdatingLearnRate = mode_updating_learn_rate_per_second*m_fFrameDuration;
+  m_fWeightUpdatingLearnRate = weight_updating_learn_rate_per_second*m_fFrameDuration;
+  m_fLowInitialModeWeight = low_init_mode_weight;
+
+  m_fModeUpdatingLearnRatePerSecond = mode_updating_learn_rate_per_second;
+  m_fWeightUpdatingLearnRatePerSecond = weight_updating_learn_rate_per_second;
+
+  m_f1_ModeUpdatingLearnRate = 1.0f - m_fModeUpdatingLearnRate;
+  m_f1_WeightUpdatingLearnRate = 1.0f - m_fWeightUpdatingLearnRate;
+}
+
+int CMultiLayerBGS::Process() {
+  BackgroundSubtractionProcess();
+  return 1;
+}
+
+int CMultiLayerBGS::SetForegroundMaskImage(IplImage* fg_mask_img) {
+  if (!fg_mask_img) {
+    printf("Please allocate the IplImage memory!\n");
+    return 0;
+  }
+  if (fg_mask_img->width != m_cvImgSize.width ||
+    fg_mask_img->height != m_cvImgSize.height ||
+    fg_mask_img->depth != IPL_DEPTH_8U ||
+    fg_mask_img->nChannels != 1) {
+      printf("Please provide the correct IplImage pointer, \ne.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);\n");
+      return 0;
+  }
+
+  m_pFgMaskImg = fg_mask_img;
+
+  return 1;
+}
+
+int CMultiLayerBGS::SetForegroundProbImage(IplImage* fg_prob_img) {
+  if (!fg_prob_img) {
+    printf("Please allocate the IplImage memory!\n");
+    return 0;
+  }
+  if (fg_prob_img->width != m_cvImgSize.width ||
+    fg_prob_img->height != m_cvImgSize.height ||
+    fg_prob_img->depth != IPL_DEPTH_8U) {
+      printf("Please provide the correct IplImage pointer, \ne.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1);\n");
+      return 0;
+  }
+
+  m_pFgProbImg = fg_prob_img;
+
+  return 1;
+}
+
+void CMultiLayerBGS::SetCurrentFrameNumber(unsigned long cur_frame_no) {
+  m_nCurImgFrameIdx = cur_frame_no;
+}
diff --git a/package_bgs/jmo/CMultiLayerBGS.h b/package_bgs/jmo/CMultiLayerBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..1eda55b1a60f59a506d3beb8a7394d8dee309bc6
--- /dev/null
+++ b/package_bgs/jmo/CMultiLayerBGS.h
@@ -0,0 +1,313 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+// BackgroundSubtraction.h: interface for the CBackgroundSubtraction class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_MULTI_LAYER_BGS_H_)
+#define _MULTI_LAYER_BGS_H_
+
+/*
+Since the used fast cross bilateral filter codes can not be compiled under Windows,
+we don't use the bilateral filter to remove the noise in the foreground detection
+step. If you compile it under Linux, please uncomment it.
+*/
+//#define LINUX_BILATERAL_FILTER
+
+#include "LocalBinaryPattern.h"
+#include "BGS.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "BlobResult.h"
+#include "OpenCvDataConversion.h"
+
+#include "BackgroundSubtractionAPI.h"
+
+#ifdef LINUX_BILATERAL_FILTER
+#include "CrossBilateralFilter.h"				// cross bilateral filter
+#endif
+
+#include <ctime>						// clock
+#include <cstdlib>						// C standard library
+#include <cstdio>						// C I/O (for sscanf)
+#include <cstring>						// string manipulation
+#include <fstream>						// file I/O
+#include <cmath>						// math includes
+#include <iostream>						// I/O streams
+
+using namespace std;						// make std:: accessible
+
+class CMultiLayerBGS : public CBackgroundSubtractionAPI
+{
+public:
+  //-------------------------------------------------------------
+  // TO CALL AT INITIALISATION: DEFINES THE SIZE OF THE INPUT IMAGES
+  // NORMALLY, UNNECESSARY IF A CONFIGURATION FILE IS LOADED
+  void   Init(int width,int height);
+
+  //-------------------------------------------------------------
+  // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND
+  // SUBTRACTION DOES NOT NEED TO BE PERFORMED
+  //
+  //  mode is useful to specify if the points to remove from
+  //  processing are in addition to the ones potentially
+  //  removed according to the configuration file,
+  //  or if they are the only ones to be removed
+  //
+  // mode=0 : provided points need to be removed
+  //          in addition to those already removed
+  // mode=1 : the provided points are the only one to remove
+  //          from processing
+  // Note:  maskImage(li,co)=0 indicate the points to remove
+  //       from background processing
+  void   SetValidPointMask(IplImage* maskImage, int mode);
+
+  //-------------------------------------------------------------
+  //
+  //   set the frame rate, to adjust the update parameters
+  //   to the actual frame rate.
+  //   Can be called only once at initialisation,
+  //   but in online cases, can be used to indicate
+  //   the time interval during the last processed frame
+  //
+  //   frameDuration is in millisecond
+  void   SetFrameRate(float    frameDuration);
+
+  //-------------------------------------------------------------
+  //
+  //   set some main parameters for background model learning.
+  //   in general, we can set large updating rates for background
+  //   model learning and set small updating rates in foreground
+  //   detection
+  void SetParameters(int max_lbp_mode_num,		// maximal LBP mode number
+    float mode_updating_learn_rate_per_second,	// background mode updating learning rate per second
+    float weight_updating_learn_rate_per_second,	// mode's weight updating learning rate per second
+    float low_init_mode_weight);			// the low initial mode weight
+
+  //-------------------------------------------------------------
+  //   PROVIDE A POINTER TO THE INPUT IMAGE
+  //   -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED
+  //
+  //   Here assumes that the input image will contain RGB images.
+  //   The memory of this image is handled by the caller.
+  //
+  //    The return value indicate whether the actual Background
+  //    Subtraction algorithm handles RGB images (1) or not (0).
+  //
+  int   SetRGBInputImage(IplImage  *  inputImage, CvRect *roi=NULL);
+
+  //-------------------------------------------------------------
+  //   PROVIDE A POINTER TO THE RESULT IMAGE
+  //   INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED
+  //
+  int SetForegroundMaskImage(IplImage* fg_mask_img);
+  int SetForegroundProbImage(IplImage* fg_prob_img);
+
+  //-------------------------------------------------------------
+  // This function should be called each time a new image is
+  // available in the input image.
+  //
+  // The return value is 0 if everything goes well, a non-zero value
+  // otherwise.
+  //
+  int   Process();
+
+  //-------------------------------------------------------------
+  // this function should save parameters and information of the model
+  // (e.g. after a training of the model, or in such a way
+  // that the model can be reload to process the next frame
+  // type of save:
+  //	0 - background model information (pixel by pixel)
+  //	1 - background model parameters
+  //	2 - both background information (pixel by pixel) and parameters
+  void   Save(const char   *bg_model_fn, int save_type);
+  void   Save(const char* bg_model_fn);
+
+  //-------------------------------------------------------------
+  // this function should load the parameters necessary
+  // for the processing of the background subtraction or
+  // load background model information
+  bool   Load(const char  *bg_model_fn);
+
+
+  void SetCurrentFrameNumber(unsigned long cur_frame_no);
+
+  void GetForegroundMaskImage(IplImage *fg_mask_img);
+  void GetForegroundImage(IplImage *fg_img, CvScalar bg_color=CV_RGB(0,255,0));
+  void GetBackgroundImage(IplImage *bk_img);
+  void GetForegroundProbabilityImage(IplImage* fg_prob_img);
+
+  void GetBgLayerNoImage(IplImage *bg_layer_no_img, CvScalar* layer_colors=NULL, int layer_num=0);
+  void GetLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, CvScalar empty_color=CV_RGB(0,0,0));
+  void GetCurrentLayeredBackgroundImage(int layered_no, IplImage *layered_bg_img, IplImage *layered_fg_img=NULL,
+    CvScalar layered_bg_bk_color=CV_RGB(0,0,0), CvScalar layered_fg_color=CV_RGB(255,0,0),
+    int smooth_win=13, float smooth_sigma=3.0f, float below_layer_noise=0.5f, float above_layer_noise=0.3f, int min_blob_size=50);
+  float DistLBP(LBPStruct *LBP1, LBPStruct *LBP2);
+  void GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors);
+  void UpdatePatternColorDistWeights(float *cur_pattern, float *bg_pattern);
+  void ExportLogMessage(char* msg);
+  void Postprocessing();
+  void GetFloatEdgeImage(IplImage *src, IplImage *dst);
+  void RemoveBackgroundLayers(PixelLBPStruct *PLBP, bool *removed_modes=NULL);
+  float CalColorRangeDist(unsigned char *cur_intensity, float *bg_intensity, float *max_intensity,
+    float *min_intensity, float shadow_rate, float highlight_rate);
+  float CalVectorsAngle(float *c1, unsigned char *c2, int length);
+  float CalVectorsNoisedAngle(float *bg_color, unsigned char *noised_color, float offset, int length);
+  void ComputeGradientImage(IplImage *src, IplImage *dst, bool bIsFloat);
+  float CalColorBgDist(uchar *cur_intensity, float *bg_intensity, float *max_intensity, float *min_intensity);
+  float CalPatternBgDist(float *cur_pattern, float *bg_pattern);
+
+  void GetForegroundMaskMap(CvMat *fg_mask_mat);
+  void Initialization(IplImage *first_img, int lbp_level_num, float *radiuses, int *neig_pt_nums);
+  void GetCurrentBackgroundDistMap(CvMat *bk_dist_map);
+  void BackgroundSubtractionProcess();
+  void SetBkMaskImage(IplImage *mask_img);
+  void SetNewImage(IplImage *new_img, CvRect *roi=NULL);
+
+  void ResetAllParameters();
+  void QuickSort(float *pData, unsigned short *pIdxes, long low, long high, bool bAscent);
+  void UpdateBgPixelPattern(float *cur_pattern, float *bg_bg_pattern);
+  void UpdateBgPixelColor(unsigned char* cur_intensity, float* bg_intensity);
+  void Update_MAX_MIN_Intensity(unsigned char *cur_intensity, float *max_intensity, float *min_intensity);
+  void MergeImages(int num, ...);
+
+  int	m_nChannel;				/* most of opencv functions support 1,2,3 or 4 channels, for the input images */
+
+  PixelLBPStruct*	m_pPixelLBPs;			/* the LBP texture patterns for each image */
+  int	m_nMaxLBPModeNum;			/* the maximal number for the used LBP pattern models */
+  float	m_fModeUpdatingLearnRate;		/* the background mode learning rate */
+  float	m_fWeightUpdatingLearnRate;		/* the background mode weight updating rate */
+  float	m_f1_ModeUpdatingLearnRate;		/* 1 - background_mode_learning_rate */
+  float	m_f1_WeightUpdatingLearnRate;		/* 1 - background_mode_weight_updating_rate */
+  float	m_fRobustColorOffset;			/* the intensity offset robust to noise */
+  float	m_fLowInitialModeWeight;		/* the lowest weight of initial background mode */
+  int	m_nLBPLength;				/* the length of texture LBP operator */
+  float	m_fPatternColorDistBgThreshold;		/* the threshold value used to classify background and foreground */
+  float	m_fPatternColorDistBgUpdatedThreshold;	/* the threshold value used to update the background modeling */
+  float	m_fMinBgLayerWeight;			/* the minimal weight to remove background layers */
+
+  int	m_nPatternDistSmoothNeigHalfSize;	/* the neighboring half size of gaussian window to remove the noise
+                                        on the distance map */
+  float	m_fPatternDistConvGaussianSigma;	/* the gaussian sigma used to remove the noise on the distance map */
+
+  float	m_fBackgroundModelPercent;		/* the background mode percent, the first several background modes
+                                      with high mode weights should be regarded as reliable background modes */
+
+  float	m_fRobustShadowRate;			/* the minimal shadow rate, [0.4, 0.7] */
+  float	m_fRobustHighlightRate;			/* the maximal highlight rate, [1.1, 1.4] */
+
+  int	m_nLBPImgNum;				/* the number of images used for texture LBP feature */
+
+  float	m_fMinLBPBinaryProb;			/* the minimal LBP binary probability */
+  float	m_f1_MinLBPBinaryProb;			/* 1 - minimal_LBP_binary_probability */
+
+  CvSize	m_cvImgSize;				/* the image size (width, height) */
+
+  unsigned long	m_nCurImgFrameIdx;			/* the frame index of current image */
+
+  bool	m_bUsedGradImage;			/* the boolean variable signaling whether the gradient image is used
+                              or not for computing LBP operator */
+
+  bool	m_bUsedColorLBP;			/* true - multi-channel color image for LBP operator,
+                              false - gray-scale image for LBP operator  */
+
+  CLocalBinaryPattern	m_cLBP;			/* the class instant for computing LBP (local binary pattern) texture feature */
+
+  IplImage* m_pBkMaskImg;				/* the mask image corresponding to the input image,
+                                i.e. all the masked pixels should be processed  */
+
+  IplImage* m_pOrgImg;				/* the original image */
+  IplImage** m_ppOrgLBPImgs;			/* the multi-layer images used for LBP feature extraction */
+  IplImage* m_pFgImg;				/* the foreground image */
+  IplImage* m_pBgImg;				/* the background image */
+  IplImage* m_pFgMaskImg;				/* the foreground mask image */
+  IplImage* m_pBgDistImg;				/* the background distance image (float) */
+  IplImage* m_pEdgeImg;				/* the edge image used for cross bilateral filter */
+  IplImage* m_pFgProbImg;				/* the foreground probability image (uchar) */
+
+  IplImage* m_pFirstAppearingTimeMap;
+
+#ifdef LINUX_BILATERAL_FILTER
+  CCrossBilateralFilter	m_cCrossBF;		/* the class instant for cross bilateral filter
+                                      which should be used to remove noise on the distance map */
+#endif
+
+  bool	m_disableLearning;
+  float	m_fSigmaS;				/* sigma in the spatial domain for cross bilateral filter */
+  float	m_fSigmaR;				/* sigma in the normalized intensity domain for cross bilateral filter */
+
+  float	m_fTextureWeight;			/* the weight value of texture LBP feature
+                              for background modeling & foreground detection */
+
+  float	m_fColorWeight;				/* the weight value of color invariant feature
+                              for background modeling & foreground detection */
+
+  float	m_fWeightUpdatingConstant;		/* the constant ( >= 1 ) for 'hysteries' weight updating scheme
+                                      (increase when matched, decrease when un-matched */
+
+  float	m_fReliableBackgroundModeWeight;	/* the weight value for background mode
+                                          which should be regarded as a reliable background mode,
+                                          which is useful for multi-layer scheme */
+
+  float	m_fMinNoisedAngle;			/* the minimal angle value between the background color
+                                and the noised observed color */
+
+  float	m_fMinNoisedAngleSine;			/* the minimal angle sine value between the background color
+                                    and the noised observed color */
+
+  float	m_fFrameDuration;			/* frame duration */
+
+  float	m_fModeUpdatingLearnRatePerSecond;
+  float	m_fWeightUpdatingLearnRatePerSecond;
+
+  int m_nLBPLevelNum;
+  float m_pLBPRadiuses[10];
+  int m_pLBPMeigPointNums[10];
+
+  CvRect* m_pROI;
+  CMultiLayerBGS();
+  virtual ~CMultiLayerBGS();
+};
+
+#endif // !defined(_MULTI_LAYER_BGS_H_)
+
diff --git a/package_bgs/jmo/LocalBinaryPattern.cpp b/package_bgs/jmo/LocalBinaryPattern.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..45528aaec04fa71a1a347ab7ca03373e95cd5360
--- /dev/null
+++ b/package_bgs/jmo/LocalBinaryPattern.cpp
@@ -0,0 +1,314 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+// LocalBinaryPattern.cpp: implementation of the CLocalBinaryPattern class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "LocalBinaryPattern.h"
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CLocalBinaryPattern::CLocalBinaryPattern()
+{
+  m_ppOrgImgs = NULL;
+  m_pRadiuses = NULL;
+  m_fRobustWhiteNoise = 3.0f;
+  m_pNeigPointsNums = NULL;
+  m_pXYShifts = NULL;
+  m_pShiftedImg = NULL;
+}
+
+CLocalBinaryPattern::~CLocalBinaryPattern()
+{
+  FreeMemories();
+}
+
+void CLocalBinaryPattern::Initialization(IplImage **first_imgs, int imgs_num, int level_num, float *radius, int *neig_pt_num, float robust_white_noise, int type)
+{
+
+  m_nImgsNum = imgs_num;
+
+  m_nLBPLevelNum = level_num;
+
+  m_pRadiuses = new float[m_nLBPLevelNum];
+  m_pNeigPointsNums= new int[m_nLBPLevelNum];
+  m_ppOrgImgs = first_imgs;
+
+  int a, b;
+  for ( a = 0 ; a < m_nImgsNum ; a++ ) {
+    m_cvImgSize = cvGetSize(first_imgs[a]);
+
+    if ( first_imgs[a]->nChannels > 1 ) {
+      printf("Input image channel must be 1!");
+      exit(1);
+    }
+  }
+
+  int tot_neig_pts_num = 0;
+  for ( a = 0 ; a < m_nLBPLevelNum ; a++ ) {
+    m_pRadiuses[a] = radius[a];
+    m_pNeigPointsNums[a] = neig_pt_num[a];
+    tot_neig_pts_num += neig_pt_num[a];
+    if ( m_pNeigPointsNums[a] % 2 != 0 ) {
+      printf("Even number must be given for points number for LBP!\n");
+      exit(1);
+    }
+  }
+
+  m_pShiftedImg = cvCloneImage(m_ppOrgImgs[0]);
+
+  m_pXYShifts = new CvPoint[tot_neig_pts_num];
+
+  m_nMaxShift.x = 0;
+  m_nMaxShift.y = 0;
+  int shift_idx = 0;
+  for ( a = 0 ; a < m_nLBPLevelNum ; a++ ) 
+    for ( b = 0 ; b < m_pNeigPointsNums[a] ; b++ ) {
+      // compute the offset of neig point
+      CalNeigPixelOffset(m_pRadiuses[a], m_pNeigPointsNums[a], b, m_pXYShifts[shift_idx].x, m_pXYShifts[shift_idx].y);
+      m_nMaxShift.x = MAX(m_nMaxShift.x, m_pXYShifts[shift_idx].x);
+      m_nMaxShift.y = MAX(m_nMaxShift.y, m_pXYShifts[shift_idx].y);
+      shift_idx++;
+    }
+
+    m_fRobustWhiteNoise = robust_white_noise;
+}
+
+void CLocalBinaryPattern::SetNewImages(IplImage **new_imgs)
+{
+  m_ppOrgImgs = new_imgs;
+}
+
+void CLocalBinaryPattern::ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi)
+{
+  float *dif_pattern;
+  float *_dif_pattern;
+  PixelLBPStruct *_PLBP;
+  int data_length;
+  float *cur_pattern;
+
+  // allocate memories
+  if ( roi ) 
+    data_length = roi->height*roi->width;
+  else
+    data_length = m_cvImgSize.width*m_cvImgSize.height;
+
+  dif_pattern = new float[data_length];
+
+  int img_idx, pt_idx, yx, level;
+  int pattern_idx = 0;
+  for ( img_idx = 0 ; img_idx < m_nImgsNum ; img_idx++ ) {
+    for ( level = 0 ; level < m_nLBPLevelNum ; level++ ) {
+      for ( pt_idx = 0 ; pt_idx < m_pNeigPointsNums[level] ; pt_idx++ ) {
+
+        // computing the shifted image
+        CalShiftedImage(m_ppOrgImgs[img_idx], m_pXYShifts[pattern_idx].x, m_pXYShifts[pattern_idx].y, m_pShiftedImg, roi);
+
+        // computing the different binary images
+        CalImageDifferenceMap(m_ppOrgImgs[img_idx], m_pShiftedImg, dif_pattern, roi);
+
+        // set the binary values
+        _PLBP = PLBP;
+        _dif_pattern = dif_pattern;
+
+        if ( roi ) {
+          int x, y;
+          for ( y = 0 ; y < roi->height ; y++ )  {
+            _PLBP = PLBP + (y+roi->y)*m_cvImgSize.width + roi->x;
+            for ( x = 0 ; x < roi->width ; x++ ) {
+              cur_pattern = (*_PLBP++).cur_pattern;
+              cur_pattern[pattern_idx] = *_dif_pattern++;
+            }
+          }
+        }
+        else {
+          for ( yx = 0 ; yx < data_length ; yx++ ) {
+            cur_pattern = (*_PLBP++).cur_pattern;
+            cur_pattern[pattern_idx] = *_dif_pattern++;
+          }
+        }
+
+        pattern_idx++;
+
+      }
+    }
+  }
+
+  // release memories
+  delete [] dif_pattern;
+
+  //delete [] shifted_dif_pattern;
+  //cvReleaseImage(&shifted_img);
+  //cvReleaseImage(&pattern_img);
+}
+
+void CLocalBinaryPattern::FreeMemories()
+{
+  if ( m_pRadiuses != NULL )
+    delete [] m_pRadiuses;
+  if ( m_pNeigPointsNums != NULL )
+    delete [] m_pNeigPointsNums;
+  if ( m_pXYShifts )
+    delete [] m_pXYShifts;
+  if ( m_pShiftedImg )
+    cvReleaseImage(&m_pShiftedImg);
+
+  m_pXYShifts = NULL;
+  m_pRadiuses = NULL;
+  m_pNeigPointsNums = NULL;
+  m_pShiftedImg = NULL;
+}
+
+void CLocalBinaryPattern::SetShiftedMeshGrid(CvSize img_size, float offset_x, float offset_y, CvMat *grid_map_x, CvMat *grid_map_y)
+{
+  float *gX = (float*)(grid_map_x->data.ptr);
+  float *gY = (float*)(grid_map_y->data.ptr);
+
+  int x, y;
+  for ( y = 0 ; y < img_size.height ; y++ ) {
+    for ( x = 0 ; x < img_size.width ; x++ ) {
+      *gX++ = (float)x + offset_x;
+      *gY++ = (float)y + offset_y;
+    }
+  }
+}
+
+void CLocalBinaryPattern::CalShiftedImage(IplImage *src, int offset_x, int offset_y, IplImage *dst, CvRect *roi)
+{
+  CvRect src_roi, dst_roi;
+  int roi_width, roi_height;
+
+  if ( roi ) {
+    src_roi.x = MAX(offset_x+roi->x, 0);
+    src_roi.y = MAX(offset_y+roi->y, 0);
+
+    dst_roi.x = MAX(-(offset_x+roi->x), roi->x);
+    dst_roi.y = MAX(-(offset_y+roi->y), roi->y);
+
+    roi_width = MIN(MIN(roi->width+(int)fabsf((float)offset_x), src->width-src_roi.x), dst->width-dst_roi.x);
+    roi_height = MIN(MIN(roi->height+(int)fabsf((float)offset_y), src->height-src_roi.y), dst->height-dst_roi.y);
+
+    src_roi.width = roi_width;
+    src_roi.height = roi_height;
+
+    dst_roi.width = roi_width;
+    dst_roi.height = roi_height;
+  }
+  else {
+    roi_width = src->width-(int)fabsf((float)offset_x);
+    roi_height = src->height-(int)fabsf((float)offset_y);
+
+    src_roi.x = MAX(offset_x, 0);
+    src_roi.y = MAX(offset_y, 0);
+    src_roi.width = roi_width;
+    src_roi.height = roi_height;
+
+    dst_roi.x = MAX(-offset_x, 0);
+    dst_roi.y = MAX(-offset_y, 0);
+    dst_roi.width = roi_width;
+    dst_roi.height = roi_height;
+  }
+
+  cvSet(dst,cvScalar(0));
+
+  if ( roi_width <= 0 || roi_height <= 0 )
+    return;
+
+  cvSetImageROI(src, src_roi);
+  cvSetImageROI(dst, dst_roi);
+  cvCopy(src, dst);
+  cvResetImageROI(src);
+  cvResetImageROI(dst);
+}
+
+void CLocalBinaryPattern::CalNeigPixelOffset(float radius, int tot_neig_pts_num, int neig_pt_idx, int &offset_x, int &offset_y)
+{
+  float angle = (float)neig_pt_idx/(float)tot_neig_pts_num*2.0f*PI;
+  offset_x = cvRound(radius*cosf(angle));
+  offset_y = cvRound(-radius*sinf(angle));
+}
+
+void CLocalBinaryPattern::CalImageDifferenceMap(IplImage *cent_img, IplImage *neig_img, float *pattern, CvRect *roi)
+{
+  COpencvDataConversion<uchar, uchar> ODC;
+
+  if ( roi ) {
+    cvSetImageROI(cent_img, *roi);
+    cvSetImageROI(neig_img, *roi);
+  }
+
+  uchar *_centI = ODC.GetImageData(cent_img);
+  uchar *_neigI = ODC.GetImageData(neig_img);
+  uchar *centI = _centI;
+  uchar *neigI = _neigI;
+
+  float *tmp_pattern = pattern;
+
+  int xy;
+  int length;
+
+  if ( roi )
+    length = roi->height*roi->width;
+  else
+    length = cent_img->height*cent_img->width;
+
+  for ( xy = 0 ; xy < length ; xy++ ) {
+    *tmp_pattern = (float)BINARY_PATTERM_ELEM(*neigI, *centI, m_fRobustWhiteNoise);
+    tmp_pattern++;
+    centI++;
+    neigI++;
+  }
+
+  if ( roi ) {
+    cvResetImageROI(cent_img);
+    cvResetImageROI(neig_img);
+  }
+
+  // release memories
+  delete [] _centI;
+  delete [] _neigI;
+
+}
+
diff --git a/package_bgs/jmo/LocalBinaryPattern.h b/package_bgs/jmo/LocalBinaryPattern.h
new file mode 100644
index 0000000000000000000000000000000000000000..307d94fb316dbefc73439342e4d5d560f64b84cf
--- /dev/null
+++ b/package_bgs/jmo/LocalBinaryPattern.h
@@ -0,0 +1,103 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+// LocalBinaryPattern.h: interface for the CLocalBinaryPattern class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_LOCAL_BINARY_PATTERN_H_)
+#define _LOCAL_BINARY_PATTERN_H_
+
+#include <cv.h>
+#include "BGS.h"
+
+
+/************************************************************************/
+/* two types of computing the LBP operators but currently GENERAL_LBP   */
+/* has been implemented.                                                */
+/************************************************************************/
+#define	GENERAL_LBP	0
+#define SYMMETRIC_LBP	1
+
+#include <cstdio>						// C I/O (for sscanf)
+#include "OpenCvDataConversion.h"
+
+
+class CLocalBinaryPattern  
+{
+public:
+  void CalImageDifferenceMap(IplImage *cent_img, IplImage *neig_img, float *pattern, CvRect *roi=NULL);
+  void CalNeigPixelOffset(float radius, int tot_neig_pts_num, int neig_pt_idx, int &offset_x, int &offset_y);
+  void CalShiftedImage(IplImage *src, int offset_x, int offset_y, IplImage *dst, CvRect *roi=NULL);
+  void FreeMemories();
+  void ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi=NULL);
+  void SetNewImages(IplImage **new_imgs);
+
+  IplImage** m_ppOrgImgs;			/* the original images used for computing the LBP operators */
+
+  void Initialization(IplImage **first_imgs, int imgs_num, 
+    int level_num, float *radius, int *neig_pt_num, 
+    float robust_white_noise = 3.0f, int type = GENERAL_LBP);
+
+  CLocalBinaryPattern();
+  virtual ~CLocalBinaryPattern();
+
+  float	m_fRobustWhiteNoise;		/* the robust noise value for computing the LBP operator in each channel */
+
+private:
+  void SetShiftedMeshGrid(CvSize img_size, float offset_x, float offset_y, CvMat *grid_map_x, CvMat *grid_map_y);
+
+  float*	m_pRadiuses;			/* the circle radiuses for the LBP operator */
+  int	m_nLBPType;			/* the type of computing LBP operator */
+  int*	m_pNeigPointsNums;		/* the numbers of neighboring pixels on multi-level circles */
+  int	m_nImgsNum;			/* the number of multi-channel image */
+  int	m_nLBPLevelNum;			/* the number of multi-level LBP operator */
+  CvSize	m_cvImgSize;			/* the image size (width, height) */
+
+  CvPoint* m_pXYShifts;
+  CvPoint	m_nMaxShift;
+
+  IplImage* m_pShiftedImg;
+};
+
+#endif // !defined(_LOCAL_BINARY_PATTERN_H_)
+
diff --git a/package_bgs/jmo/MultiLayerBGS.cpp b/package_bgs/jmo/MultiLayerBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc0a6e88a318d017f34ac4cc46cac7931b8fc2b5
--- /dev/null
+++ b/package_bgs/jmo/MultiLayerBGS.cpp
@@ -0,0 +1,332 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "MultiLayerBGS.h"
+
+MultiLayerBGS::MultiLayerBGS() : firstTime(true), showOutput(true), 
+  bg_model_preload(""), saveModel(false), disableLearning(false), disableDetectMode(true), loadDefaultParams(true), 
+  detectAfter(0), frameNumber(0)
+{
+  std::cout << "MultiLayerBGS()" << std::endl;
+}
+
+MultiLayerBGS::~MultiLayerBGS()
+{
+  finish();
+  std::cout << "~MultiLayerBGS()" << std::endl;
+}
+
+void MultiLayerBGS::setStatus(Status _status)
+{
+  status = _status;
+}
+
+void MultiLayerBGS::finish(void)
+{
+  if(bg_model_preload.empty())
+  {
+    bg_model_preload = "./models/MultiLayerBGSModel.yml";
+    saveConfig();
+  }
+
+  if(status == MLBGS_LEARN && saveModel == true)
+  {
+    std::cout << "MultiLayerBGS saving background model: " << bg_model_preload << std::endl;
+    BGS->Save(bg_model_preload.c_str());
+  }
+
+  cvReleaseImage(&fg_img);
+  cvReleaseImage(&bg_img);
+  cvReleaseImage(&fg_prob_img);
+  cvReleaseImage(&fg_mask_img);
+  cvReleaseImage(&fg_prob_img3);
+  cvReleaseImage(&merged_img);
+
+  delete BGS;
+}
+
+void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  CvSize img_size = cvSize(cvCeil((double) img_input.size().width), cvCeil((double) img_input.size().height));
+
+  if(firstTime)
+  {
+    if(disableDetectMode)
+      status = MLBGS_LEARN;
+
+    if(status == MLBGS_LEARN)
+      std::cout << "MultiLayerBGS in LEARN mode" << std::endl;
+
+    if(status == MLBGS_DETECT)
+      std::cout << "MultiLayerBGS in DETECT mode" << std::endl;
+
+    org_img = new IplImage(img_input);
+
+    fg_img = cvCreateImage(img_size, org_img->depth, org_img->nChannels);
+    bg_img = cvCreateImage(img_size, org_img->depth, org_img->nChannels);
+    fg_prob_img = cvCreateImage(img_size, org_img->depth, 1);
+    fg_mask_img = cvCreateImage(img_size, org_img->depth, 1);
+    fg_prob_img3 = cvCreateImage(img_size, org_img->depth, org_img->nChannels);
+    merged_img = cvCreateImage(cvSize(img_size.width * 2, img_size.height * 2), org_img->depth, org_img->nChannels);
+
+    BGS = new CMultiLayerBGS();
+    BGS->Init(img_size.width, img_size.height);
+    BGS->SetForegroundMaskImage(fg_mask_img);
+    BGS->SetForegroundProbImage(fg_prob_img);
+
+    if(bg_model_preload.empty() == false)
+    {
+      std::cout << "MultiLayerBGS loading background model: " << bg_model_preload << std::endl;
+      BGS->Load(bg_model_preload.c_str());
+    }
+
+    if(status == MLBGS_DETECT)
+    {
+      BGS->m_disableLearning = disableLearning;
+
+      if(disableLearning)
+        std::cout << "MultiLayerBGS disabled learning in DETECT mode" << std::endl;
+      else
+        std::cout << "MultiLayerBGS enabled learning in DETECT mode" << std::endl;
+    }
+
+    if(loadDefaultParams)
+    {
+      std::cout << "MultiLayerBGS loading default params" << std::endl;
+
+      max_mode_num = 5;
+      weight_updating_constant = 5.0;
+      texture_weight = 0.5;
+      bg_mode_percent = 0.6;
+      pattern_neig_half_size = 4;
+      pattern_neig_gaus_sigma = 3.0;
+      bg_prob_threshold = 0.2;
+      bg_prob_updating_threshold = 0.2;
+      robust_LBP_constant = 3;
+      min_noised_angle = 10.0 / 180.0 * PI; //0,01768
+      shadow_rate = 0.6;
+      highlight_rate = 1.2;
+      bilater_filter_sigma_s = 3.0;
+      bilater_filter_sigma_r = 0.1;
+    }
+    else
+      std::cout << "MultiLayerBGS loading config params" << std::endl;
+
+    BGS->m_nMaxLBPModeNum = max_mode_num;
+    BGS->m_fWeightUpdatingConstant = weight_updating_constant;
+    BGS->m_fTextureWeight = texture_weight;
+    BGS->m_fBackgroundModelPercent = bg_mode_percent;
+    BGS->m_nPatternDistSmoothNeigHalfSize = pattern_neig_half_size;
+    BGS->m_fPatternDistConvGaussianSigma = pattern_neig_gaus_sigma;
+    BGS->m_fPatternColorDistBgThreshold = bg_prob_threshold;
+    BGS->m_fPatternColorDistBgUpdatedThreshold = bg_prob_updating_threshold;
+    BGS->m_fRobustColorOffset = robust_LBP_constant;
+    BGS->m_fMinNoisedAngle = min_noised_angle;
+    BGS->m_fRobustShadowRate = shadow_rate;
+    BGS->m_fRobustHighlightRate = highlight_rate;
+    BGS->m_fSigmaS = bilater_filter_sigma_s;
+    BGS->m_fSigmaR = bilater_filter_sigma_r;
+
+    if(loadDefaultParams)
+    {
+      //frame_duration = 1.0 / 30.0;
+      //frame_duration = 1.0 / 25.0;
+      frame_duration = 1.0 / 10.0;
+    }
+
+    BGS->SetFrameRate(frame_duration);
+
+    if(status == MLBGS_LEARN)
+    {
+      if(loadDefaultParams)
+      {
+        mode_learn_rate_per_second = 0.5;
+        weight_learn_rate_per_second = 0.5;
+        init_mode_weight = 0.05;
+      }
+      else
+      {
+        mode_learn_rate_per_second = learn_mode_learn_rate_per_second;
+        weight_learn_rate_per_second = learn_weight_learn_rate_per_second;
+        init_mode_weight = learn_init_mode_weight;
+      }
+    }
+
+    if(status == MLBGS_DETECT)
+    {
+      if(loadDefaultParams)
+      {
+        mode_learn_rate_per_second = 0.01;
+        weight_learn_rate_per_second = 0.01;
+        init_mode_weight = 0.001;
+      }
+      else
+      {
+        mode_learn_rate_per_second = detect_mode_learn_rate_per_second;
+        weight_learn_rate_per_second = detect_weight_learn_rate_per_second;
+        init_mode_weight = detect_init_mode_weight;
+      }
+    }
+
+    BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight);
+
+    saveConfig();
+
+    delete org_img;
+  }
+  
+  //IplImage* inputImage = new IplImage(img_input);
+  //IplImage* img = cvCreateImage(img_size, IPL_DEPTH_8U, 3);
+  //cvCopy(inputImage, img);
+  //delete inputImage;
+
+  if(detectAfter > 0 && detectAfter == frameNumber)
+  {
+    std::cout << "MultiLayerBGS in DETECT mode" << std::endl;
+
+    status = MLBGS_DETECT;
+
+    mode_learn_rate_per_second = 0.01;
+    weight_learn_rate_per_second = 0.01;
+    init_mode_weight = 0.001;
+
+    BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight);
+
+    BGS->m_disableLearning = disableLearning;
+
+    if(disableLearning)
+      std::cout << "MultiLayerBGS disabled learning in DETECT mode" << std::endl;
+    else
+      std::cout << "MultiLayerBGS enabled learning in DETECT mode" << std::endl;
+  }
+
+  IplImage* img = new IplImage(img_input);
+
+  BGS->SetRGBInputImage(img);
+  BGS->Process();
+  
+  BGS->GetBackgroundImage(bg_img);
+  BGS->GetForegroundImage(fg_img);
+  BGS->GetForegroundProbabilityImage(fg_prob_img3);
+  BGS->GetForegroundMaskImage(fg_mask_img);
+  BGS->MergeImages(4, img, bg_img, fg_prob_img3, fg_img, merged_img);
+
+  img_merged = cv::Mat(merged_img);
+  img_foreground = cv::Mat(fg_mask_img);
+  img_background = cv::Mat(bg_img);
+
+  if(showOutput)
+  {
+    cv::imshow("MLBGS Layers", img_merged);
+    cv::imshow("MLBGS FG Mask", img_foreground);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+  
+  delete img;
+  //cvReleaseImage(&img);
+
+  firstTime = false;
+  frameNumber++;
+}
+
+void MultiLayerBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MultiLayerBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteString(fs, "preloadModel", bg_model_preload.c_str());
+  cvWriteInt(fs, "saveModel", saveModel);
+  cvWriteInt(fs, "detectAfter", detectAfter);
+  cvWriteInt(fs, "disableDetectMode", disableDetectMode);
+  cvWriteInt(fs, "disableLearningInDetecMode", disableLearning);
+  cvWriteInt(fs, "loadDefaultParams", loadDefaultParams);
+  
+  cvWriteInt(fs, "max_mode_num", max_mode_num);
+  cvWriteReal(fs, "weight_updating_constant", weight_updating_constant);
+  cvWriteReal(fs, "texture_weight", texture_weight);
+  cvWriteReal(fs, "bg_mode_percent", bg_mode_percent);
+  cvWriteInt(fs, "pattern_neig_half_size", pattern_neig_half_size);
+  cvWriteReal(fs, "pattern_neig_gaus_sigma", pattern_neig_gaus_sigma);
+  cvWriteReal(fs, "bg_prob_threshold", bg_prob_threshold);
+  cvWriteReal(fs, "bg_prob_updating_threshold", bg_prob_updating_threshold);
+  cvWriteInt(fs, "robust_LBP_constant", robust_LBP_constant);
+  cvWriteReal(fs, "min_noised_angle", min_noised_angle);
+  cvWriteReal(fs, "shadow_rate", shadow_rate);
+  cvWriteReal(fs, "highlight_rate", highlight_rate);
+  cvWriteReal(fs, "bilater_filter_sigma_s", bilater_filter_sigma_s);
+  cvWriteReal(fs, "bilater_filter_sigma_r", bilater_filter_sigma_r);
+
+  cvWriteReal(fs, "frame_duration", frame_duration);
+
+  cvWriteReal(fs, "learn_mode_learn_rate_per_second", learn_mode_learn_rate_per_second);
+  cvWriteReal(fs, "learn_weight_learn_rate_per_second", learn_weight_learn_rate_per_second);
+  cvWriteReal(fs, "learn_init_mode_weight", learn_init_mode_weight);
+  
+  cvWriteReal(fs, "detect_mode_learn_rate_per_second", detect_mode_learn_rate_per_second);
+  cvWriteReal(fs, "detect_weight_learn_rate_per_second", detect_weight_learn_rate_per_second);
+  cvWriteReal(fs, "detect_init_mode_weight", detect_init_mode_weight);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void MultiLayerBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MultiLayerBGS.xml", 0, CV_STORAGE_READ);
+  
+  bg_model_preload = cvReadStringByName(fs, 0, "preloadModel", "");
+  saveModel = cvReadIntByName(fs, 0, "saveModel", false);
+  detectAfter = cvReadIntByName(fs, 0, "detectAfter", 0);
+  disableDetectMode = cvReadIntByName(fs, 0, "disableDetectMode", true);
+  disableLearning = cvReadIntByName(fs, 0, "disableLearningInDetecMode", false);
+  loadDefaultParams = cvReadIntByName(fs, 0, "loadDefaultParams", true);
+
+  max_mode_num = cvReadIntByName(fs, 0, "max_mode_num", 5);
+  weight_updating_constant = cvReadRealByName(fs, 0, "weight_updating_constant", 5.0);
+  texture_weight = cvReadRealByName(fs, 0, "texture_weight", 0.5);
+  bg_mode_percent = cvReadRealByName(fs, 0, "bg_mode_percent", 0.6);
+  pattern_neig_half_size = cvReadIntByName(fs, 0, "pattern_neig_half_size", 4);
+  pattern_neig_gaus_sigma = cvReadRealByName(fs, 0, "pattern_neig_gaus_sigma", 3.0);
+  bg_prob_threshold = cvReadRealByName(fs, 0, "bg_prob_threshold", 0.2);
+  bg_prob_updating_threshold = cvReadRealByName(fs, 0, "bg_prob_updating_threshold", 0.2);
+  robust_LBP_constant = cvReadIntByName(fs, 0, "robust_LBP_constant", 3);
+  min_noised_angle = cvReadRealByName(fs, 0, "min_noised_angle", 0.01768);
+  shadow_rate = cvReadRealByName(fs, 0, "shadow_rate", 0.6);
+  highlight_rate = cvReadRealByName(fs, 0, "highlight_rate", 1.2);
+  bilater_filter_sigma_s = cvReadRealByName(fs, 0, "bilater_filter_sigma_s", 3.0);
+  bilater_filter_sigma_r = cvReadRealByName(fs, 0, "bilater_filter_sigma_r", 0.1);
+
+  frame_duration = cvReadRealByName(fs, 0, "frame_duration", 0.1);
+
+  learn_mode_learn_rate_per_second = cvReadRealByName(fs, 0, "learn_mode_learn_rate_per_second", 0.5);
+  learn_weight_learn_rate_per_second = cvReadRealByName(fs, 0, "learn_weight_learn_rate_per_second", 0.5);
+  learn_init_mode_weight = cvReadRealByName(fs, 0, "learn_init_mode_weight", 0.05);
+  
+  detect_mode_learn_rate_per_second = cvReadRealByName(fs, 0, "detect_mode_learn_rate_per_second", 0.01);
+  detect_weight_learn_rate_per_second = cvReadRealByName(fs, 0, "detect_weight_learn_rate_per_second", 0.01);
+  detect_init_mode_weight = cvReadRealByName(fs, 0, "detect_init_mode_weight", 0.001);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/jmo/MultiLayerBGS.h b/package_bgs/jmo/MultiLayerBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..671a788c76e277f9b2b020e04a7413e6b3ace0ff
--- /dev/null
+++ b/package_bgs/jmo/MultiLayerBGS.h
@@ -0,0 +1,101 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "CMultiLayerBGS.h"
+
+class MultiLayerBGS : public IBGS
+{
+public:
+  enum Status
+  {
+    MLBGS_NONE   = -1,
+    MLBGS_LEARN  = 0,
+    MLBGS_DETECT = 1
+  };
+
+private:
+  bool firstTime;
+  long long frameNumber;
+  cv::Mat img_foreground;
+  cv::Mat img_merged;
+  cv::Mat img_background;
+  bool showOutput;
+  bool saveModel;
+  bool disableDetectMode;
+  bool disableLearning;
+  int detectAfter;
+  CMultiLayerBGS* BGS;
+  Status status;
+  IplImage* img;
+  IplImage* org_img;
+  IplImage* fg_img;
+  IplImage* bg_img;
+  IplImage* fg_prob_img;
+  IplImage* fg_mask_img;
+  IplImage* fg_prob_img3;
+  IplImage* merged_img;
+  std::string bg_model_preload;
+  
+  bool loadDefaultParams;
+
+  int max_mode_num;
+  float weight_updating_constant;
+  float texture_weight;
+  float bg_mode_percent;
+  int pattern_neig_half_size;
+  float pattern_neig_gaus_sigma;
+  float bg_prob_threshold;
+  float bg_prob_updating_threshold;
+  int robust_LBP_constant;
+  float min_noised_angle;
+  float shadow_rate;
+  float highlight_rate;
+  float bilater_filter_sigma_s;
+  float bilater_filter_sigma_r;
+
+  float frame_duration;
+
+  float mode_learn_rate_per_second;
+  float weight_learn_rate_per_second;
+  float init_mode_weight;
+
+  float learn_mode_learn_rate_per_second;
+  float learn_weight_learn_rate_per_second;
+  float learn_init_mode_weight;
+  
+  float detect_mode_learn_rate_per_second;
+  float detect_weight_learn_rate_per_second;
+  float detect_init_mode_weight;
+
+public:
+  MultiLayerBGS();
+  ~MultiLayerBGS();
+
+  void setStatus(Status status);
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void finish(void);
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/jmo/OpenCvDataConversion.h b/package_bgs/jmo/OpenCvDataConversion.h
new file mode 100644
index 0000000000000000000000000000000000000000..22d6ec90302e09760e4af3c944d4abee5631b166
--- /dev/null
+++ b/package_bgs/jmo/OpenCvDataConversion.h
@@ -0,0 +1,224 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+// OpencvDataConversion.h: interface for the COpencvDataConversion class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(_OPENCV_DATA_CONVERSION_H_)
+#define _OPENCV_DATA_CONVERSION_H_
+
+#include <cv.h>
+#include <stdio.h>
+
+template <class TI, class TM>		/* class TI - the type of image data, class TM - the type of matrix data */
+class COpencvDataConversion
+{
+public:
+
+  /* get the image data */
+  TI * GetImageData(IplImage *img) 
+  {
+    if ( !img->roi ) {	/* no ROI used, i.e. the whole image */
+      int y; //, x;
+      TI* img_data = new TI[img->width*img->height*img->nChannels];
+      TI* temp = img_data;
+      TI* x_data;
+
+      for ( y = 0 ; y < img->height ; y++ ) {
+        x_data = (TI*)(img->imageData + img->widthStep*y);
+        int row_length = img->width*img->nChannels;
+        memcpy(temp, x_data, sizeof(TI)*row_length);
+        temp += row_length;
+        /*
+        for ( x = 0 ; x < img->width*img->nChannels ; x++ ) 
+        *temp++ = *x_data++;
+        */
+      }
+
+      return img_data;
+    }
+    else {	/* get image data only in ROI */
+      int y;//, x;
+      TI* img_data = new TI[img->roi->width*img->roi->height*img->nChannels];
+      TI* temp = img_data;
+      TI* x_data;
+      for ( y = img->roi->yOffset ; y < img->roi->yOffset+img->roi->height ; y++ ) {
+        x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels);
+        int row_length = img->roi->width*img->nChannels;
+        memcpy(temp, x_data, sizeof(TI)*row_length);
+        temp += row_length;
+        /*
+        for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ ) 
+        *temp++ = *x_data++;
+        */
+      }
+      return img_data;
+    }
+  };
+
+  /* set the image data */
+  void SetImageData(IplImage *img, TI *img_data) 
+  {
+    if ( !img->roi ) {	/* no ROI used, i.e. the whole image */
+      int y;//, x;
+      TI* temp = img_data;
+      TI* x_data;
+      for ( y = 0 ; y < img->height ; y++ ) {
+        x_data = (TI*)(img->imageData + img->widthStep*y);
+        int row_length = img->width*img->nChannels;
+        memcpy(x_data, temp, sizeof(TI)*row_length);
+        temp += row_length;
+        /*
+        for ( x = 0 ; x < img->width*img->nChannels ; x++ ) 
+        *x_data++ = *temp++;
+        */
+      }
+    }
+    else {	/* set image data only in ROI */
+      int y;//, x;
+      TI* temp = img_data;
+      TI* x_data;
+      for ( y = img->roi->yOffset ; y < img->roi->yOffset+img->roi->height ; y++ ) {
+        x_data = (TI*)(img->imageData + img->widthStep*y + img->roi->xOffset*sizeof(TI)*img->nChannels);
+        int row_length = img->roi->width*img->nChannels;
+        memcpy(x_data, temp, sizeof(TI)*row_length);
+        temp += row_length;
+        /*
+        for ( x = 0 ; x < img->roi->width*img->nChannels ; x++ ) 
+        *x_data++ = *temp++;
+        */
+      }
+    }
+  }
+
+  /* get the matrix data */
+  TM * GetMatData(CvMat *mat) 
+  {
+    TM* mat_data = new TM[mat->width*mat->height];
+    memcpy(mat_data, mat->data.ptr, sizeof(TM)*mat->width*mat->height);
+    return mat_data;
+
+    /*
+    int y, x;
+    TM* mat_data = new TM[mat->width*mat->height];
+    TM* temp = mat_data;
+    TM* x_data;
+    for ( y = 0 ; y < mat->height ; y++ ) {
+    x_data = (TM*)(mat->data.ptr + mat->step*y);
+    for ( x = 0 ; x < mat->width ; x++ ) 
+    *temp++ = *x_data++;
+    }
+    return mat_data;
+    */
+  };
+
+  /* set the matrix data */
+  void SetMatData(CvMat *mat, TM *mat_data) 
+  {
+    memcpy(mat->data.ptr, mat_data, sizeof(TM)*mat->width*mat->height);
+
+    /*
+    int y, x;
+    TM* temp = mat_data;
+    TM* x_data;
+    for ( y = 0 ; y < mat->height ; y++ ) {
+    x_data = (TM*)(mat->data.ptr + mat->step*y);
+    for ( x = 0 ; x < mat->width ; x++ ) 
+    *x_data++ = *temp++;
+    }
+    */
+  }
+
+  /* convert the image data to the matrix data */
+  void ConvertData(IplImage *img_src, CvMat *mat_dst) 
+  {
+    if ( img_src->nChannels > 1 ) {
+      printf("Must be one-channel image for ConvertImageData!\n");
+      exit(1);
+    }
+
+    TI* _img_data = GetImageData(img_src);
+    TM* _mat_data = new TM[img_src->width*img_src->height];
+
+    TI* img_data = _img_data;
+    TM* mat_data = _mat_data;
+    int i;
+    for ( i = 0 ; i < img_src->width*img_src->height ; i++ )
+      *mat_data++ = (TM)(*img_data++);
+
+    SetMatData(mat_dst, _mat_data);
+
+    delete [] _img_data;
+    delete [] _mat_data;
+  }
+
+  /* convert the matrix data to the image data */
+  void ConvertData(CvMat *mat_src, IplImage *img_dst)
+  {
+    if ( img_dst->nChannels > 1 ) {
+      printf("Must be one-channel image for ConvertImageData!\n");
+      exit(1);
+    }
+
+    TM* _mat_data = GetMatData(mat_src);
+    TI* _img_data = new TI[mat_src->width*mat_src->height];
+
+    TM* mat_data = _mat_data;
+    TI* img_data = _img_data;
+
+    int i;
+    for ( i = 0 ; i < mat_src->width*mat_src->height ; i++ )
+      *img_data++ = (TI)(*mat_data++);
+
+    SetImageData(img_dst, _img_data);
+
+    delete [] _img_data;
+    delete [] _mat_data;
+  }
+
+  COpencvDataConversion() {};
+  virtual ~COpencvDataConversion() {};
+};
+
+#endif // !defined(_OPENCV_DATA_CONVERSION_H_)
+
diff --git a/package_bgs/jmo/blob.cpp b/package_bgs/jmo/blob.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2b99b2a52ef9a61366659ed9322deca3317a9440
--- /dev/null
+++ b/package_bgs/jmo/blob.cpp
@@ -0,0 +1,1149 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/************************************************************************
+Blob.cpp
+
+- FUNCIONALITAT: Implementaci� de la classe CBlob
+- AUTOR: Inspecta S.L.
+MODIFICACIONS (Modificaci�, Autor, Data):
+
+
+FUNCTIONALITY: Implementation of the CBlob class and some helper classes to perform
+some calculations on it
+AUTHOR: Inspecta S.L.
+MODIFICATIONS (Modification, Author, Date):
+
+**************************************************************************/
+
+
+#include <limits.h>
+#include "blob.h"
+#include "cv.h"
+
+namespace Blob
+{
+
+/**
+- FUNCI�: CBlob
+- FUNCIONALITAT: Constructor est�ndard 
+- PAR�METRES:
+- RESULTAT:
+- inicialitzaci� de totes les variables internes i de l'storage i la sequencia
+per a les cantonades del blob
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlob
+- FUNCTIONALITY: Standard constructor
+- PARAMETERS:
+- RESULT:
+- memory allocation for the blob edges and initialization of member variables
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlob::CBlob()
+{
+  etiqueta = -1;		// Flag indicates null region
+  exterior = 0;
+  area = 0.0f;
+  perimeter = 0.0f;
+  parent = -1;
+  minx = LONG_MAX;
+  maxx = 0;
+  miny = LONG_MAX;
+  maxy = 0;
+  sumx = 0;
+  sumy = 0;
+  sumxx = 0;
+  sumyy = 0;
+  sumxy = 0;
+  mean = 0;
+  stddev = 0;
+  externPerimeter = 0;
+
+  m_storage = cvCreateMemStorage(0);
+  edges = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2,
+    sizeof(CvContour),
+    sizeof(CvPoint),m_storage);
+}
+
+/**
+- FUNCI�: CBlob
+- FUNCIONALITAT: Constructor de c�pia 
+- PAR�METRES:
+- RESULTAT:
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlob
+- FUNCTIONALITY: Copy constructor
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlob::CBlob( const CBlob &src )
+{
+  // copiem les propietats del blob origen a l'actual
+  etiqueta = src.etiqueta;		
+  exterior = src.exterior;
+  area = src.Area();
+  perimeter = src.Perimeter();
+  parent = src.parent;
+  minx = src.minx;
+  maxx = src.maxx;
+  miny = src.miny;
+  maxy = src.maxy;
+  sumx = src.sumx;
+  sumy = src.sumy;
+  sumxx = src.sumxx;
+  sumyy = src.sumyy;
+  sumxy = src.sumxy;
+  mean = src.mean;
+  stddev = src.stddev;
+  externPerimeter = src.externPerimeter;
+
+  // copiem els edges del blob origen a l'actual
+  CvSeqReader reader;
+  CvSeqWriter writer;
+  CvPoint edgeactual;
+
+  // creem una sequencia buida per als edges
+  m_storage = cvCreateMemStorage(0);
+  edges = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2,
+    sizeof(CvContour),
+    sizeof(CvPoint),m_storage);
+
+  cvStartReadSeq( src.Edges(), &reader);
+  cvStartAppendToSeq( edges, &writer );
+
+  for( int i=0; i< src.Edges()->total; i++)
+  {
+    CV_READ_SEQ_ELEM( edgeactual ,reader);
+    CV_WRITE_SEQ_ELEM( edgeactual , writer );
+  }
+
+  cvEndWriteSeq( &writer );
+}
+CBlob::CBlob( const CBlob *src )
+{
+  // copiem les propietats del blob origen a l'actual
+  etiqueta = src->etiqueta;		
+  exterior = src->exterior;
+  area = src->Area();
+  perimeter = src->Perimeter();
+  parent = src->parent;
+  minx = src->minx;
+  maxx = src->maxx;
+  miny = src->miny;
+  maxy = src->maxy;
+  sumx = src->sumx;
+  sumy = src->sumy;
+  sumxx = src->sumxx;
+  sumyy = src->sumyy;
+  sumxy = src->sumxy;
+  mean = src->mean;
+  stddev = src->stddev;
+  externPerimeter = src->externPerimeter;
+
+  // copiem els edges del blob origen a l'actual
+  CvSeqReader reader;
+  CvSeqWriter writer;
+  CvPoint edgeactual;
+
+  // creem una sequencia buida per als edges
+  m_storage = cvCreateMemStorage(0);
+  edges = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2,
+    sizeof(CvContour),
+    sizeof(CvPoint),m_storage);
+
+  cvStartReadSeq( src->Edges(), &reader);
+  cvStartAppendToSeq( edges, &writer );
+
+  for( int i=0; i< src->Edges()->total; i++)
+  {
+    CV_READ_SEQ_ELEM( edgeactual ,reader);
+    CV_WRITE_SEQ_ELEM( edgeactual , writer );
+  }
+
+  cvEndWriteSeq( &writer );
+}
+
+/**
+- FUNCI�: ~CBlob
+- FUNCIONALITAT: Destructor est�ndard 
+- PAR�METRES:
+- RESULTAT:
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlob
+- FUNCTIONALITY: Standard destructor
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlob::~CBlob()
+{
+  // Eliminar v�rtexs del blob 
+  cvClearSeq(edges);
+  // i la zona de mem�ria on s�n
+  cvReleaseMemStorage( &m_storage );
+}
+
+/**
+- FUNCI�: operator=
+- FUNCIONALITAT: Operador d'assignaci�
+- PAR�METRES:
+- src: blob a assignar a l'actual
+- RESULTAT:
+- Substitueix el blob actual per el src
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: Assigment operator
+- FUNCTIONALITY: Assigns a blob to the current 
+- PARAMETERS:
+- src: blob to assign
+- RESULT:
+- the current blob is replaced by the src blob
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CBlob& CBlob::operator=(const CBlob &src )
+{
+  // si ja s�n el mateix, no cal fer res
+  if (this != &src)
+  {
+    // Eliminar v�rtexs del blob 
+    cvClearSeq(edges);
+    // i la zona de mem�ria on s�n
+    cvReleaseMemStorage( &m_storage );
+
+    // creem una sequencia buida per als edges
+    m_storage = cvCreateMemStorage(0);
+    edges = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2,
+      sizeof(CvContour),
+      sizeof(CvPoint),m_storage);
+
+    // copiem les propietats del blob origen a l'actual
+    etiqueta = src.etiqueta;		
+    exterior = src.exterior;
+    area = src.Area();
+    perimeter = src.Perimeter();
+    parent = src.parent;
+    minx = src.minx;
+    maxx = src.maxx;
+    miny = src.miny;
+    maxy = src.maxy;
+    sumx = src.sumx;
+    sumy = src.sumy;
+    sumxx = src.sumxx;
+    sumyy = src.sumyy;
+    sumxy = src.sumxy;
+    mean = src.mean;
+    stddev = src.stddev;
+    externPerimeter = src.externPerimeter;
+
+    // copiem els edges del blob origen a l'actual
+    CvSeqReader reader;
+    CvSeqWriter writer;
+    CvPoint edgeactual;
+
+    cvStartReadSeq( src.Edges(), &reader);
+    cvStartAppendToSeq( edges, &writer );
+
+    for( int i=0; i< src.Edges()->total; i++)
+    {
+      CV_READ_SEQ_ELEM( edgeactual ,reader);
+      CV_WRITE_SEQ_ELEM( edgeactual , writer );
+    }
+
+    cvEndWriteSeq( &writer );
+  }
+  return *this;
+}
+
+/**
+- FUNCI�: FillBlob
+- FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat
+- PAR�METRES:
+- imatge: imatge on es vol pintar el el blob
+- color: color amb que es vol pintar el blob
+- RESULTAT:
+- retorna la imatge d'entrada amb el blob pintat
+- RESTRICCIONS:
+- AUTOR: 
+- Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: FillBlob
+- FUNCTIONALITY: 
+- Fills the blob with a specified colour
+- PARAMETERS:
+- imatge: where to paint
+- color: colour to paint the blob
+- RESULT:
+- modifies input image and returns the seed point used to fill the blob
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlob::FillBlob( IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const					  
+{
+
+  //verifiquem que existeixi el blob i que tingui cantonades
+  if( edges == NULL || edges->total == 0 ) return;
+
+  CvPoint edgeactual, pt1, pt2;
+  CvSeqReader reader;
+  vectorPunts vectorEdges = vectorPunts( edges->total );
+  vectorPunts::iterator itEdges, itEdgesSeguent;
+  bool dinsBlob;
+  int yActual;
+
+  // passem els punts del blob a un vector de punts de les STL
+  cvStartReadSeq( edges, &reader);
+  itEdges = vectorEdges.begin();
+  while( itEdges != vectorEdges.end() )
+  {
+    CV_READ_SEQ_ELEM( edgeactual ,reader);
+    *itEdges = edgeactual;
+    itEdges++;
+  }
+  // ordenem el vector per les Y's i les X's d'esquerra a dreta
+  std::sort( vectorEdges.begin(), vectorEdges.end(), comparaCvPoint() );
+
+  // recorrem el vector ordenat i fem linies entre punts consecutius
+  itEdges = vectorEdges.begin();
+  itEdgesSeguent = vectorEdges.begin() + 1;
+  dinsBlob = true;
+  while( itEdges != (vectorEdges.end() - 1))
+  {
+    yActual = (*itEdges).y;
+
+    if( ( (*itEdges).x != (*itEdgesSeguent).x ) &&
+      ( (*itEdgesSeguent).y == yActual )
+      )
+    {
+      if( dinsBlob )
+      {
+        pt1 = *itEdges;
+        pt1.x += offsetX;
+        pt1.y += offsetY;
+
+        pt2 = *itEdgesSeguent;
+        pt2.x += offsetX;
+        pt2.y += offsetY;
+
+        cvLine( imatge, pt1, pt2, color );
+      }
+      dinsBlob =! dinsBlob;
+    }
+    itEdges++;
+    itEdgesSeguent++;
+    if( (*itEdges).y != yActual ) dinsBlob = true;
+  }
+  vectorEdges.clear();
+}
+
+/**
+- FUNCI�: CopyEdges
+- FUNCIONALITAT: Afegeix els v�rtexs del blob al blob destination
+- PAR�METRES:
+- destination: blob al que volem afegir els v�rtexs
+- RESULTAT:
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CopyEdges
+- FUNCTIONALITY: Adds the blob edges to destination
+- PARAMETERS:
+- destination: where to add the edges
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlob::CopyEdges( CBlob &destination ) const
+{
+  CvSeqReader reader;
+  CvSeqWriter writer;
+  CvPoint edgeactual;
+
+  cvStartReadSeq( edges, &reader);
+  cvStartAppendToSeq( destination.Edges(), &writer );
+
+  for( int i=0; i<edges->total; i++)
+  {
+    CV_READ_SEQ_ELEM( edgeactual ,reader);
+    CV_WRITE_SEQ_ELEM( edgeactual , writer );
+  }
+
+  cvEndWriteSeq( &writer );
+}
+
+/**
+- FUNCI�: ClearEdges
+- FUNCIONALITAT: Elimina els v�rtexs del blob
+- PAR�METRES:
+- RESULTAT:
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: ClearEdges
+- FUNCTIONALITY: Delete current blob edges
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+void CBlob::ClearEdges()
+{
+  // Eliminar v�rtexs del blob eliminat
+  cvClearSeq( edges );
+}
+
+/**
+- FUNCI�: GetConvexHull
+- FUNCIONALITAT: Retorna el poligon convex del blob
+- PAR�METRES:
+- dst: sequencia on desarem el resultat (no ha d'estar inicialitzada)
+- RESULTAT:
+- true si tot ha anat b�
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: GetConvexHull
+- FUNCTIONALITY: Calculates the convex hull polygon of the blob
+- PARAMETERS:
+- dst: where to store the result
+- RESULT:
+- true if no error ocurred
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+bool CBlob::GetConvexHull( CvSeq **dst ) const
+{
+  if( edges != NULL && edges->total > 0)
+  {
+    *dst = cvConvexHull2( edges, 0, CV_CLOCKWISE, 0 );
+    return true;
+  }
+  return false;
+}
+
+/**
+- FUNCI�: GetEllipse
+- FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob
+- PAR�METRES:
+- RESULTAT:
+- estructura amb l'ellipse
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 25-05-2005.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: GetEllipse
+- FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob
+- PARAMETERS:
+- RESULT:
+- CvBox2D struct with the calculated ellipse
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+CvBox2D CBlob::GetEllipse() const
+{
+  CvBox2D elipse;
+  // necessitem 6 punts per calcular l'elipse
+  if( edges != NULL && edges->total > 6)
+  {
+    elipse = cvFitEllipse2( edges );
+  }
+  else
+  {
+    elipse.center.x = 0.0;
+    elipse.center.y = 0.0;
+    elipse.size.width = 0.0;
+    elipse.size.height = 0.0;
+    elipse.angle = 0.0;
+  }
+  return elipse;
+}
+
+
+
+/***************************************************************************
+Implementaci� de les classes per al c�lcul de caracter�stiques sobre el blob
+
+Implementation of the helper classes to perform operations on blobs
+**************************************************************************/
+
+/**
+- FUNCI�: Moment
+- FUNCIONALITAT: Calcula el moment pq del blob
+- RESULTAT:
+- retorna el moment pq especificat o 0 si el moment no est� implementat
+- RESTRICCIONS:
+- Implementats els moments pq: 00, 01, 10, 20, 02
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: Moment
+- FUNCTIONALITY: Calculates the pq moment of the blob
+- PARAMETERS:
+- RESULT:
+- returns the pq moment or 0 if the moment it is not implemented
+- RESTRICTIONS:
+- Currently, only implemented the 00, 01, 10, 20, 02 pq moments
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 20-07-2004.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetMoment::operator()(const CBlob &blob) const
+{
+  //Moment 00
+  if((m_p==0) && (m_q==0))
+    return blob.Area();
+
+  //Moment 10
+  if((m_p==1) && (m_q==0))
+    return blob.SumX();
+
+  //Moment 01
+  if((m_p==0) && (m_q==1))
+    return blob.SumY();
+
+  //Moment 20
+  if((m_p==2) && (m_q==0))
+    return blob.SumXX();
+
+  //Moment 02
+  if((m_p==0) && (m_q==2))
+    return blob.SumYY();
+
+  return 0;
+}
+
+/**
+- FUNCI�: HullPerimeter
+- FUNCIONALITAT: Calcula la longitud del perimetre convex del blob.
+Fa servir la funci� d'OpenCV cvConvexHull2 per a 
+calcular el perimetre convex.
+
+- PAR�METRES:
+- RESULTAT:
+- retorna la longitud del per�metre convex del blob. Si el blob no t� coordenades
+associades retorna el per�metre normal del blob.
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobGetHullPerimeter
+- FUNCTIONALITY: Calculates the convex hull perimeter of the blob
+- PARAMETERS:
+- RESULT:
+- returns the convex hull perimeter of the blob or the perimeter if the 
+blob edges could not be retrieved
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetHullPerimeter::operator()(const CBlob &blob) const
+{
+  if(blob.Edges() != NULL && blob.Edges()->total > 0)
+  {
+    CvSeq *hull = cvConvexHull2( blob.Edges(), 0, CV_CLOCKWISE, 1 );
+    return fabs(cvArcLength(hull,CV_WHOLE_SEQ,1));
+  }
+  return blob.Perimeter();
+}
+
+double CBlobGetHullArea::operator()(const CBlob &blob) const
+{
+  if(blob.Edges() != NULL && blob.Edges()->total > 0)
+  {
+    CvSeq *hull = cvConvexHull2( blob.Edges(), 0, CV_CLOCKWISE, 1 );
+    return fabs(cvContourArea(hull));
+  }
+  return blob.Perimeter();
+}
+
+/**
+- FUNCI�: MinX_at_MinY
+- FUNCIONALITAT: Calcula el valor MinX a MinY.
+- PAR�METRES:
+- blob: blob del que volem calcular el valor
+- RESULTAT:
+- retorna la X minima en la Y minima.
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobGetMinXatMinY
+- FUNCTIONALITY: Calculates the minimum X on the minimum Y
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetMinXatMinY::operator()(const CBlob &blob) const
+{
+  double MinX_at_MinY = LONG_MAX;
+
+  CvSeqReader reader;
+  CvPoint edgeactual;
+
+  cvStartReadSeq(blob.Edges(),&reader);
+
+  for(int j=0;j<blob.Edges()->total;j++)
+  {
+    CV_READ_SEQ_ELEM(edgeactual,reader);
+    if( (edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY) )
+    {
+      MinX_at_MinY = edgeactual.x;
+    }
+  }
+
+  return MinX_at_MinY;
+}
+
+/**
+- FUNCI�: MinY_at_MaxX
+- FUNCIONALITAT: Calcula el valor MinX a MaxX.
+- PAR�METRES:
+- blob: blob del que volem calcular el valor
+- RESULTAT:
+- retorna la Y minima en la X maxima.
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobGetMinXatMinY
+- FUNCTIONALITY: Calculates the minimum Y on the maximum X
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const
+{
+  double MinY_at_MaxX = LONG_MAX;
+
+  CvSeqReader reader;
+  CvPoint edgeactual;
+
+  cvStartReadSeq(blob.Edges(),&reader);
+
+  for(int j=0;j<blob.Edges()->total;j++)
+  {
+    CV_READ_SEQ_ELEM(edgeactual,reader);
+    if( (edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX) )
+    {
+      MinY_at_MaxX = edgeactual.y;
+    }
+  }
+
+  return MinY_at_MaxX;
+}
+
+/**
+- FUNCI�: MaxX_at_MaxY
+- FUNCIONALITAT: Calcula el valor MaxX a MaxY.
+- PAR�METRES:
+- blob: blob del que volem calcular el valor
+- RESULTAT:
+- retorna la X maxima en la Y maxima.
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobGetMaxXatMaxY
+- FUNCTIONALITY: Calculates the maximum X on the maximum Y
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const
+{
+  double MaxX_at_MaxY = LONG_MIN;
+
+  CvSeqReader reader;
+  CvPoint edgeactual;
+
+  cvStartReadSeq(blob.Edges(),&reader);
+
+  for(int j=0;j<blob.Edges()->total;j++)
+  {
+    CV_READ_SEQ_ELEM(edgeactual,reader);
+    if( (edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY) )
+    {
+      MaxX_at_MaxY = edgeactual.x;
+    }
+  }
+
+  return MaxX_at_MaxY;
+}
+
+/**
+- FUNCI�: MaxY_at_MinX
+- FUNCIONALITAT: Calcula el valor MaxY a MinX.
+- PAR�METRES:
+- blob: blob del que volem calcular el valor
+- RESULTAT:
+- retorna la Y maxima en la X minima.
+- RESTRICCIONS:
+- AUTOR: Ricard Borr�s
+- DATA DE CREACI�: 20-07-2004.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: CBlobGetMaxYatMinX
+- FUNCTIONALITY: Calculates the maximum Y on the minimum X
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const
+{
+  double MaxY_at_MinX = LONG_MIN;
+
+  CvSeqReader reader;
+  CvPoint edgeactual;
+
+  cvStartReadSeq(blob.Edges(),&reader);
+
+  for(int j=0;j<blob.Edges()->total;j++)
+  {
+    CV_READ_SEQ_ELEM(edgeactual,reader);
+    if( (edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX) )
+    {
+      MaxY_at_MinX = edgeactual.y;
+    }
+  }
+
+  return MaxY_at_MinX;
+}
+
+/**
+Retorna l'elongaci� del blob (longitud/amplada)
+*/
+/**
+- FUNCTION: CBlobGetElongation
+- FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth )
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- See below to see how the lenght and the breadth are aproximated
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetElongation::operator()(const CBlob &blob) const
+{
+  double ampladaC,longitudC,amplada,longitud;
+
+  ampladaC=(double) (blob.Perimeter()+sqrt(pow(blob.Perimeter(),2)-16*blob.Area()))/4;
+  if(ampladaC<=0.0) return 0;
+  longitudC=(double) blob.Area()/ampladaC;
+
+  longitud=MAX( longitudC , ampladaC );
+  amplada=MIN( longitudC , ampladaC );
+
+  return (double) longitud/amplada;
+}
+
+/**
+Retorna la compacitat del blob
+*/
+/**
+- FUNCTION: CBlobGetCompactness
+- FUNCTIONALITY: Calculates the compactness of the blob 
+( maximum for circle shaped blobs, minimum for the rest)
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetCompactness::operator()(const CBlob &blob) const
+{
+  if( blob.Area() != 0.0 )
+    return (double) pow(blob.Perimeter(),2)/(4*CV_PI*blob.Area());
+  else
+    return 0.0;
+}
+
+/**
+Retorna la rugositat del blob
+*/
+/**
+- FUNCTION: CBlobGetRoughness
+- FUNCTIONALITY: Calculates the roughness of the blob 
+( ratio between perimeter and convex hull perimeter)
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetRoughness::operator()(const CBlob &blob) const
+{
+  CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter();
+
+  double hullPerimeter = getHullPerimeter(blob);
+
+  if( hullPerimeter != 0.0 )
+    return blob.Perimeter() / hullPerimeter;//HullPerimeter();
+
+  return 0.0;
+}
+
+/**
+Retorna la longitud del blob
+*/
+/**
+- FUNCTION: CBlobGetLength
+- FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob)
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- The lenght is an aproximation to the real lenght
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetLength::operator()(const CBlob &blob) const
+{
+  double ampladaC,longitudC;
+  double tmp;
+
+  tmp = blob.Perimeter()*blob.Perimeter() - 16*blob.Area();
+
+  if( tmp > 0.0 )
+    ampladaC = (double) (blob.Perimeter()+sqrt(tmp))/4;
+  // error intr�nsec en els c�lculs de l'�rea i el per�metre 
+  else
+    ampladaC = (double) (blob.Perimeter())/4;
+
+  if(ampladaC<=0.0) return 0;
+  longitudC=(double) blob.Area()/ampladaC;
+
+  return MAX( longitudC , ampladaC );
+}
+
+/**
+Retorna l'amplada del blob
+*/
+/**
+- FUNCTION: CBlobGetBreadth
+- FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob)
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- The breadth is an aproximation to the real breadth
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetBreadth::operator()(const CBlob &blob) const
+{
+  double ampladaC,longitudC;
+  double tmp;
+
+  tmp = blob.Perimeter()*blob.Perimeter() - 16*blob.Area();
+
+  if( tmp > 0.0 )
+    ampladaC = (double) (blob.Perimeter()+sqrt(tmp))/4;
+  // error intr�nsec en els c�lculs de l'�rea i el per�metre 
+  else
+    ampladaC = (double) (blob.Perimeter())/4;
+
+  if(ampladaC<=0.0) return 0;
+  longitudC = (double) blob.Area()/ampladaC;
+
+  return MIN( longitudC , ampladaC );
+}
+
+/**
+Calcula la dist�ncia entre un punt i el centre del blob
+*/
+/**
+- FUNCTION: CBlobGetDistanceFromPoint
+- FUNCTIONALITY: Calculates the euclidean distance between the blob center and 
+the point specified in the constructor
+- PARAMETERS:
+- RESULT:
+- RESTRICTIONS:
+- AUTHOR: Ricard Borr�s
+- CREATION DATE: 25-05-2005.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const
+{
+  double xmitjana, ymitjana;
+  CBlobGetXCenter getXCenter;
+  CBlobGetYCenter getYCenter;
+
+  xmitjana = m_x - getXCenter( blob );
+  ymitjana = m_y - getYCenter( blob );
+
+  return sqrt((xmitjana*xmitjana)+(ymitjana*ymitjana));
+}
+
+/**
+- FUNCI�: BlobGetXYInside
+- FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular
+del blob
+- RESULTAT:
+- retorna 1 si hi est�; 0 si no
+- RESTRICCIONS:
+- AUTOR: Francesc Pinyol Margalef
+- DATA DE CREACI�: 16-01-2006.
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+/**
+- FUNCTION: BlobGetXYInside
+- FUNCTIONALITY: Calculates whether a point is inside the
+rectangular bounding box of a blob
+- PARAMETERS:
+- RESULT:
+- returns 1 if it is inside; o if not
+- RESTRICTIONS:
+- AUTHOR: Francesc Pinyol Margalef
+- CREATION DATE: 16-01-2006.
+- MODIFICATION: Date. Author. Description.
+*/
+double CBlobGetXYInside::operator()(const CBlob &blob) const
+{
+  if( blob.Edges() == NULL || blob.Edges()->total == 0 ) return 0.0;
+
+  // passem els punts del blob a un vector de punts de les STL
+  CvSeqReader reader;
+  CBlob::vectorPunts vectorEdges;
+  CBlob::vectorPunts::iterator itEdges, itEdgesSeguent;
+  CvPoint edgeactual;
+  bool dinsBlob;
+
+  // agafem tots els punts amb la mateixa y que l'actual
+  cvStartReadSeq( blob.Edges(), &reader);
+
+  for( int i=0; i< blob.Edges()->total; i++)
+  {
+    CV_READ_SEQ_ELEM( edgeactual ,reader );
+    if( edgeactual.y == m_p.y )
+      vectorEdges.push_back( edgeactual );
+  }
+
+  if( vectorEdges.size() == 0 ) return 0.0;
+
+  // ordenem el vector per les Y's i les X's d'esquerra a dreta
+  std::sort( vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint() );
+
+  // recorrem el punts del blob de la mateixa fila que el punt d'entrada
+  // i mirem si la X del punt d'entrada est� entre dos coordenades "plenes"
+  // del blob
+  itEdges = vectorEdges.begin();
+  itEdgesSeguent = vectorEdges.begin() + 1;
+  dinsBlob = true;
+
+  while( itEdges != (vectorEdges.end() - 1) )
+  {
+    if( (*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob )
+    {
+      vectorEdges.clear();
+      return 1.0;
+    }
+
+    itEdges++;
+    itEdgesSeguent++;
+    dinsBlob = !dinsBlob;
+  }
+
+  vectorEdges.clear();
+  return 0.0;
+}
+
+#ifdef BLOB_OBJECT_FACTORY
+
+/**
+- FUNCI�: RegistraTotsOperadors
+- FUNCIONALITAT: Registrar tots els operadors definits a blob.h
+- PAR�METRES:
+- fabricaOperadorsBlob: f�brica on es registraran els operadors
+- RESULTAT:
+- Modifica l'objecte fabricaOperadorsBlob
+- RESTRICCIONS:
+- Nom�s es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb 
+el m�tode Register de la f�brica.
+- AUTOR: rborras
+- DATA DE CREACI�: 2006/05/18
+- MODIFICACI�: Data. Autor. Descripci�.
+*/
+void RegistraTotsOperadors( t_OperadorBlobFactory &fabricaOperadorsBlob )
+{
+  // blob shape
+  fabricaOperadorsBlob.Register( CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>());
+  fabricaOperadorsBlob.Register( CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>());
+  fabricaOperadorsBlob.Register( CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>());
+  fabricaOperadorsBlob.Register( CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>());
+  fabricaOperadorsBlob.Register( CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>());
+  fabricaOperadorsBlob.Register( CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>());
+  fabricaOperadorsBlob.Register( CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>());
+  fabricaOperadorsBlob.Register( CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>());
+
+  // extern pixels
+  fabricaOperadorsBlob.Register( CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>());
+  fabricaOperadorsBlob.Register( CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>());
+  fabricaOperadorsBlob.Register( CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>());
+
+
+  // hull 
+  fabricaOperadorsBlob.Register( CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>());
+  fabricaOperadorsBlob.Register( CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>());
+
+
+  // elipse info
+  fabricaOperadorsBlob.Register( CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>());
+  fabricaOperadorsBlob.Register( CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>());
+  fabricaOperadorsBlob.Register( CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>());
+  fabricaOperadorsBlob.Register( CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>());
+  fabricaOperadorsBlob.Register( CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>());
+  fabricaOperadorsBlob.Register( CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>());
+
+  // min an max
+  fabricaOperadorsBlob.Register( CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>());
+  fabricaOperadorsBlob.Register( CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>());
+  fabricaOperadorsBlob.Register( CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>());
+  fabricaOperadorsBlob.Register( CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>());
+
+  fabricaOperadorsBlob.Register( CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>());
+  fabricaOperadorsBlob.Register( CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>());
+  fabricaOperadorsBlob.Register( CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>());
+  fabricaOperadorsBlob.Register( CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>());
+
+  // grey level stats
+  fabricaOperadorsBlob.Register( CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>());
+  fabricaOperadorsBlob.Register( CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>());
+
+  // coordinate info
+  fabricaOperadorsBlob.Register( CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>());
+  fabricaOperadorsBlob.Register( CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>());
+  fabricaOperadorsBlob.Register( CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>());
+  fabricaOperadorsBlob.Register( CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>());
+  fabricaOperadorsBlob.Register( CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>());
+  fabricaOperadorsBlob.Register( CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>());
+
+  // moments
+  fabricaOperadorsBlob.Register( CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>());
+
+}
+
+#endif
+
+}
+
diff --git a/package_bgs/jmo/blob.h b/package_bgs/jmo/blob.h
new file mode 100644
index 0000000000000000000000000000000000000000..463e81acd05d4d4ec02230ac53aca7796f6b531e
--- /dev/null
+++ b/package_bgs/jmo/blob.h
@@ -0,0 +1,853 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* --- --- ---
+* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch)
+* All rights reserved.
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+* 3. The name of the author may not be used to endorse or promote products
+*    derived from this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/************************************************************************
+Blob.h
+
+FUNCIONALITAT: Definici� de la classe CBlob
+AUTOR: Inspecta S.L.
+MODIFICACIONS (Modificaci�, Autor, Data):
+
+FUNCTIONALITY: Definition of the CBlob class and some helper classes to perform
+some calculations on it
+AUTHOR: Inspecta S.L.
+MODIFICATIONS (Modification, Author, Date):
+
+**************************************************************************/
+
+//! Disable warnings referred to 255 character truncation for the std:map
+//#pragma warning( disable : 4786 ) 
+
+#ifndef CBLOB_INSPECTA_INCLUDED
+#define CBLOB_INSPECTA_INCLUDED
+
+#include "cxcore.h"
+#include "BlobLibraryConfiguration.h"
+#include <functional>
+#include <vector>
+#include <algorithm>
+
+
+#ifdef BLOB_OBJECT_FACTORY
+//! Object factory pattern implementation
+#include "..\inspecta\DesignPatterns\ObjectFactory.h"
+#endif
+
+
+//! Factor de conversi� de graus a radians
+#define DEGREE2RAD		(CV_PI / 180.0)
+
+namespace Blob
+{
+
+/**
+Classe que representa un blob, ent�s com un conjunt de pixels del 
+mateix color contigus en una imatge binaritzada.
+
+Class to represent a blob, a group of connected pixels in a binary image
+*/
+class CBlob
+{
+public:
+  //! Constructor est�ndard
+  //! Standard constructor
+  CBlob();
+  //! Constructor de c�pia
+  //! Copy constructor
+  CBlob( const CBlob &src );
+  CBlob( const CBlob *src );
+
+  //! Destructor est�ndard
+  //! Standard Destructor
+  ~CBlob();
+
+  //! Operador d'assignaci�
+  //! Assigment operator
+  CBlob& operator=(const CBlob &src );
+
+  //! Indica si el blob est� buit ( no t� cap info associada )
+  //! Shows if the blob has associated information
+  bool IsEmpty() const
+  {
+    return (area == 0.0 && perimeter == 0.0 );
+  };
+
+  //! Neteja les cantonades del blob
+  //! Clears the edges of the blob
+  void ClearEdges();
+  //! Copia les cantonades del blob a un altre (les afegeix al dest�)
+  //! Adds the blob edges to another blob
+  void CopyEdges( CBlob &destination ) const;
+  //! Retorna el poligon convex del blob
+  //! Calculates the convex hull of the blob
+  bool GetConvexHull( CvSeq **dst ) const;
+  //! Calcula l'elipse que s'adapta als v�rtexs del blob
+  //! Fits an ellipse to the blob edges
+  CvBox2D GetEllipse() const;
+
+  //! Pinta l'interior d'un blob d'un color determinat
+  //! Paints the blob in an image
+  void FillBlob( IplImage *imatge, CvScalar color, int offsetX = 0, int offsetY = 0 ) const;
+
+  //! Funcions GET sobre els valors dels blobs
+  //! Get functions
+
+  inline int Label() const	{ return etiqueta; }
+  inline int Parent() const	{ return parent; }
+  inline double Area() const { return area; }
+  inline double Perimeter() const { return perimeter; }
+  inline double ExternPerimeter() const { return externPerimeter; }
+  inline int	  Exterior() const { return exterior; }
+  inline double Mean() const { return mean; }
+  inline double StdDev() const { return stddev; }
+  inline double MinX() const { return minx; }
+  inline double MinY() const { return miny; }
+  inline double MaxX() const { return maxx; }
+  inline double MaxY() const { return maxy; }
+  inline CvSeq *Edges() const { return edges; }
+  inline double SumX() const { return sumx; }
+  inline double SumY() const { return sumy; }
+  inline double SumXX() const { return sumxx; }
+  inline double SumYY() const { return sumyy; }
+  inline double SumXY() const { return sumxy; }
+
+  //! etiqueta del blob
+  //! label of the blob
+  int etiqueta;
+  //! flag per indicar si es exterior o no
+  //! true for extern blobs
+  int exterior;
+  //! area del blob
+  //! Blob area
+  double area;
+  //! perimetre del blob
+  //! Blob perimeter
+  double perimeter;
+  //! quantitat de perimetre del blob extern
+  //! amount of blob perimeter which is exterior
+  double externPerimeter;
+  //! etiqueta del blob pare
+  //! label of the parent blob
+  int parent;
+  //! moments
+  double sumx;
+  double sumy;
+  double sumxx;
+  double sumyy;
+  double sumxy;
+  //! Bounding rect
+  double minx;
+  double maxx;
+  double miny;
+  double maxy;
+
+  //! mitjana
+  //! mean of the grey scale values of the blob pixels
+  double mean;
+  //! desviaci� standard
+  //! standard deviation of the grey scale values of the blob pixels
+  double stddev;
+
+  //! �rea de mem�ria on es desaran els punts de contorn del blob
+  //! storage which contains the edges of the blob
+  CvMemStorage *m_storage;
+  //!	Sequ�ncia de punts del contorn del blob
+  //! Sequence with the edges of the blob
+  CvSeq *edges;
+
+
+  //! Point datatype for plotting (FillBlob)
+  typedef std::vector<CvPoint> vectorPunts;
+
+  //! Helper class to compare two CvPoints (for sorting in FillBlob)
+  struct comparaCvPoint : public std::binary_function<CvPoint, CvPoint, bool> 
+  {
+    //! Definim que un punt �s menor com m�s amunt a la dreta estigui
+    bool operator()(CvPoint a, CvPoint b) 
+    { 
+      if( a.y == b.y ) 
+        return a.x < b.x;
+      else 
+        return a.y < b.y; 
+    }
+  };
+};
+
+
+
+/**************************************************************************
+Definici� de les classes per a fer operacions sobre els blobs
+
+Helper classes to perform operations on blobs
+**************************************************************************/
+
+
+//! Classe d'on derivarem totes les operacions sobre els blobs
+//! Interface to derive all blob operations
+class COperadorBlob
+{
+public:
+  virtual ~COperadorBlob(){};
+
+  //! Aplica l'operaci� al blob
+  virtual double operator()(const CBlob &blob) const = 0;
+  //! Obt� el nom de l'operador
+  virtual const char *GetNom() const = 0;
+
+  operator COperadorBlob*() const
+  {
+    return (COperadorBlob*)this;
+  }
+};
+
+typedef COperadorBlob funcio_calculBlob;
+
+#ifdef BLOB_OBJECT_FACTORY
+/**
+Funci� per comparar dos identificadors dins de la f�brica de COperadorBlobs
+*/
+struct functorComparacioIdOperador
+{
+  bool operator()(const char* s1, const char* s2) const
+  {
+    return strcmp(s1, s2) < 0;
+  }
+};
+
+//! Definition of Object factory type for COperadorBlob objects
+typedef ObjectFactory<COperadorBlob, const char *, functorComparacioIdOperador > t_OperadorBlobFactory;
+
+//! Funci� global per a registrar tots els operadors definits a blob.h
+void RegistraTotsOperadors( t_OperadorBlobFactory &fabricaOperadorsBlob );
+
+#endif
+
+//! Classe per calcular l'�rea d'un blob
+//! Class to get the area of a blob
+class CBlobGetArea : public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  { 
+    return blob.Area(); 
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetArea";
+  }
+};
+
+//! Classe per calcular el perimetre d'un blob
+//! Class to get the perimeter of a blob
+class CBlobGetPerimeter: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  { 
+    return blob.Perimeter(); 
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetPerimeter";
+  }
+};
+
+//! Classe que diu si un blob �s extern o no
+//! Class to get the extern flag of a blob
+class CBlobGetExterior: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  { 
+    return blob.Exterior(); 
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetExterior";
+  }
+};
+
+//! Classe per calcular la mitjana de nivells de gris d'un blob
+//! Class to get the mean grey level of a blob
+class CBlobGetMean: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  { 
+    return blob.Mean(); 
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMean";
+  }
+};
+
+//! Classe per calcular la desviaci� est�ndard dels nivells de gris d'un blob
+//! Class to get the standard deviation of the grey level values of a blob
+class CBlobGetStdDev: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  { 
+    return blob.StdDev(); 
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetStdDev";
+  }
+};
+
+//! Classe per calcular la compacitat d'un blob
+//! Class to calculate the compactness of a blob
+class CBlobGetCompactness: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetCompactness";
+  }
+};
+
+//! Classe per calcular la longitud d'un blob
+//! Class to calculate the length of a blob
+class CBlobGetLength: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetLength";
+  }
+};
+
+//! Classe per calcular l'amplada d'un blob
+//! Class to calculate the breadth of a blob
+class CBlobGetBreadth: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetBreadth";
+  }
+};
+
+//! Classe per calcular la difer�ncia en X del blob
+class CBlobGetDiffX: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.maxx - blob.minx;
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetDiffX";
+  }
+};
+
+//! Classe per calcular la difer�ncia en X del blob
+class CBlobGetDiffY: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.maxy - blob.miny;
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetDiffY";
+  }
+};
+
+//! Classe per calcular el moment PQ del blob
+//! Class to calculate the P,Q moment of a blob
+class CBlobGetMoment: public COperadorBlob
+{
+public:
+  //! Constructor est�ndard
+  //! Standard constructor (gets the 00 moment)
+  CBlobGetMoment()
+  {
+    m_p = m_q = 0;
+  }
+  //! Constructor: indiquem el moment p,q a calcular
+  //! Constructor: gets the PQ moment
+  CBlobGetMoment( int p, int q )
+  {
+    m_p = p;
+    m_q = q;
+  };
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetMoment";
+  }
+
+private:
+  //! moment que volem calcular
+  int m_p, m_q;
+};
+
+//! Classe per calcular el perimetre del poligon convex d'un blob
+//! Class to calculate the convex hull perimeter of a blob
+class CBlobGetHullPerimeter: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetHullPerimeter";
+  }
+};
+
+//! Classe per calcular l'�rea del poligon convex d'un blob
+//! Class to calculate the convex hull area of a blob
+class CBlobGetHullArea: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetHullArea";
+  }
+};
+
+//! Classe per calcular la x minima en la y minima
+//! Class to calculate the minimum x on the minimum y
+class CBlobGetMinXatMinY: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetMinXatMinY";
+  }
+};
+
+//! Classe per calcular la y minima en la x maxima
+//! Class to calculate the minimum y on the maximum x
+class CBlobGetMinYatMaxX: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetMinYatMaxX";
+  }
+};
+
+//! Classe per calcular la x maxima en la y maxima
+//! Class to calculate the maximum x on the maximum y
+class CBlobGetMaxXatMaxY: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetMaxXatMaxY";
+  }
+};
+
+//! Classe per calcular la y maxima en la x minima
+//! Class to calculate the maximum y on the minimum y
+class CBlobGetMaxYatMinX: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetMaxYatMinX";
+  }
+};
+
+//! Classe per a calcular la x m�nima
+//! Class to get the minimum x
+class CBlobGetMinX: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.MinX();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMinX";
+  }
+};
+
+//! Classe per a calcular la x m�xima
+//! Class to get the maximum x
+class CBlobGetMaxX: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.MaxX();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMaxX";
+  }
+};
+
+//! Classe per a calcular la y m�nima
+//! Class to get the minimum y
+class CBlobGetMinY: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.MinY();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMinY";
+  }
+};
+
+//! Classe per a calcular la y m�xima
+//! Class to get the maximum y
+class CBlobGetMaxY: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.MaxY();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMax";
+  }
+};
+
+
+//! Classe per calcular l'elongacio d'un blob
+//! Class to calculate the elongation of the blob
+class CBlobGetElongation: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetElongation";
+  }
+};
+
+//! Classe per calcular la rugositat d'un blob
+//! Class to calculate the roughness of the blob
+class CBlobGetRoughness: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetRoughness";
+  }
+};
+
+//! Classe per calcular la dist�ncia entre el centre del blob i un punt donat
+//! Class to calculate the euclidean distance between the center of a blob and a given point
+class CBlobGetDistanceFromPoint: public COperadorBlob
+{
+public:
+  //! Standard constructor (distance to point 0,0)
+  CBlobGetDistanceFromPoint()
+  {
+    m_x = m_y = 0.0;
+  }
+  //! Constructor (distance to point x,y)
+  CBlobGetDistanceFromPoint( const double x, const double y )
+  {
+    m_x = x;
+    m_y = y;
+  }
+
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetDistanceFromPoint";
+  }
+
+private:
+  // coordenades del punt on volem calcular la dist�ncia
+  double m_x, m_y;
+};
+
+//! Classe per calcular el nombre de pixels externs d'un blob
+//! Class to get the number of extern pixels of a blob
+class CBlobGetExternPerimeter: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.ExternPerimeter();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetExternPerimeter";
+  }
+};
+
+//! Classe per calcular el ratio entre el perimetre i nombre pixels externs
+//! valors propers a 0 indiquen que la majoria del blob �s intern
+//! valors propers a 1 indiquen que la majoria del blob �s extern
+//! Class to calculate the ratio between the perimeter and the number of extern pixels
+class CBlobGetExternPerimeterRatio: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    if( blob.Perimeter() != 0 )
+      return blob.ExternPerimeter() / blob.Perimeter();
+    else
+      return blob.ExternPerimeter();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetExternPerimeterRatio";
+  }
+};
+
+//! Classe per calcular el ratio entre el perimetre convex i nombre pixels externs
+//! valors propers a 0 indiquen que la majoria del blob �s intern
+//! valors propers a 1 indiquen que la majoria del blob �s extern
+//! Class to calculate the ratio between the perimeter and the number of extern pixels
+class CBlobGetExternHullPerimeterRatio: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    CBlobGetHullPerimeter getHullPerimeter;
+    double hullPerimeter;
+
+    if( (hullPerimeter = getHullPerimeter( blob ) ) != 0 )
+      return blob.ExternPerimeter() / hullPerimeter;
+    else
+      return blob.ExternPerimeter();
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetExternHullPerimeterRatio";
+  }
+};
+
+//! Classe per calcular el centre en el eix X d'un blob
+//! Class to calculate the center in the X direction
+class CBlobGetXCenter: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.MinX() + (( blob.MaxX() - blob.MinX() ) / 2.0);
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetXCenter";
+  }
+};
+
+//! Classe per calcular el centre en el eix Y d'un blob
+//! Class to calculate the center in the Y direction
+class CBlobGetYCenter: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    return blob.MinY() + (( blob.MaxY() - blob.MinY() ) / 2.0);
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetYCenter";
+  }
+};
+
+//! Classe per calcular la longitud de l'eix major d'un blob
+//! Class to calculate the length of the major axis of the ellipse that fits the blob edges
+class CBlobGetMajorAxisLength: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    CvBox2D elipse = blob.GetEllipse();
+
+    return elipse.size.width;
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMajorAxisLength";
+  }
+};
+
+//! Classe per calcular el ratio entre l'area de la elipse i la de la taca
+//! Class 
+class CBlobGetAreaElipseRatio: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    if( blob.Area()==0.0 ) return 0.0;
+
+    CvBox2D elipse = blob.GetEllipse();
+    double ratioAreaElipseAreaTaca = ( (elipse.size.width/2.0)
+      *
+      (elipse.size.height/2.0)
+      *CV_PI
+      )
+      /
+      blob.Area();
+
+    return ratioAreaElipseAreaTaca;
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetAreaElipseRatio";
+  }
+};
+
+//! Classe per calcular la longitud de l'eix menor d'un blob
+//! Class to calculate the length of the minor axis of the ellipse that fits the blob edges
+class CBlobGetMinorAxisLength: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    CvBox2D elipse = blob.GetEllipse();
+
+    return elipse.size.height;
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetMinorAxisLength";
+  }
+};
+
+//! Classe per calcular l'orientaci� de l'ellipse del blob en radians
+//! Class to calculate the orientation of the ellipse that fits the blob edges in radians
+class CBlobGetOrientation: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    CvBox2D elipse = blob.GetEllipse();
+
+    if( elipse.angle > 180.0 )
+      return (( elipse.angle - 180.0 )* DEGREE2RAD);
+    else
+      return ( elipse.angle * DEGREE2RAD);
+
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetOrientation";
+  }
+};
+
+//! Classe per calcular el cosinus de l'orientaci� de l'ellipse del blob
+//! Class to calculate the cosinus of the orientation of the ellipse that fits the blob edges
+class CBlobGetOrientationCos: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    CBlobGetOrientation getOrientation;
+    return fabs( cos( getOrientation(blob) ));
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetOrientationCos";
+  }
+};
+
+
+//! Classe per calcular el ratio entre l'eix major i menor de la el�lipse
+//! Class to calculate the ratio between both axes of the ellipse
+class CBlobGetAxisRatio: public COperadorBlob
+{
+public:
+  double operator()(const CBlob &blob) const
+  {
+    CvBox2D elipse = blob.GetEllipse();
+
+    return elipse.size.height / elipse.size.width;
+  }
+  const char *GetNom() const
+  {
+    return "CBlobGetAxisRatio";
+  }
+};
+
+
+//! Classe per calcular si un punt cau dins del blob
+//! Class to calculate whether a point is inside a blob
+class CBlobGetXYInside: public COperadorBlob
+{
+public:
+  //! Constructor est�ndard
+  //! Standard constructor
+  CBlobGetXYInside()
+  {
+    m_p = cvPoint(0,0);
+  }
+  //! Constructor: indiquem el punt
+  //! Constructor: sets the point
+  CBlobGetXYInside( CvPoint p )
+  {
+    m_p = p;
+  };
+  double operator()(const CBlob &blob) const;
+  const char *GetNom() const
+  {
+    return "CBlobGetXYInside";
+  }
+
+private:
+  //! punt que considerem
+  //! point to be considered
+  CvPoint m_p;
+};
+
+}
+
+#endif //CBLOB_INSPECTA_INCLUDED
+
diff --git a/package_bgs/lb/BGModel.cpp b/package_bgs/lb/BGModel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c42bec73e34dfb1dd83dc319bbb8569281521a62
--- /dev/null
+++ b/package_bgs/lb/BGModel.cpp
@@ -0,0 +1,87 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+  BGModel.cpp
+    
+  Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BGModel.h"
+
+namespace lb_library
+{
+  BGModel::BGModel(int width, int height): m_width(width), m_height(height)
+  {
+    m_SrcImage = cvCreateImage(cvSize(m_width,m_height), IPL_DEPTH_8U, 3);
+    m_BGImage = cvCreateImage(cvSize(m_width,m_height), IPL_DEPTH_8U, 3);
+    m_FGImage = cvCreateImage(cvSize(m_width,m_height), IPL_DEPTH_8U, 3);
+
+    cvZero(m_SrcImage);
+    cvZero(m_BGImage);
+    cvZero(m_FGImage);
+  }
+
+  BGModel::~BGModel()
+  {
+    if (m_SrcImage!=NULL) cvReleaseImage(&m_SrcImage);
+    if (m_BGImage!=NULL) cvReleaseImage(&m_BGImage);
+    if (m_FGImage!=NULL) cvReleaseImage(&m_FGImage);
+  }
+
+  IplImage* BGModel::GetSrc()
+  {
+    return m_SrcImage;
+  }
+
+  IplImage* BGModel::GetFG()
+  {
+    return m_FGImage;
+  }
+
+  IplImage* BGModel::GetBG()
+  {
+    return m_BGImage;
+  }
+
+  void BGModel::InitModel(IplImage* image)
+  {
+    cvCopy(image,m_SrcImage);
+    Init();
+    return;
+  }
+
+  void BGModel::UpdateModel(IplImage* image)
+  {
+    cvCopy(image,m_SrcImage);
+    Update();
+    return;
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/lb/BGModel.h b/package_bgs/lb/BGModel.h
new file mode 100644
index 0000000000000000000000000000000000000000..d53b52e7729e9ecdfbe326054c0bc2fff1fc1a86
--- /dev/null
+++ b/package_bgs/lb/BGModel.h
@@ -0,0 +1,78 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+  BGModel.h
+    
+  Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef BGMODEL_H
+#define BGMODEL_H
+
+#include <cv.h>
+#include <math.h>
+#include <float.h>
+
+#include "Types.h"
+
+namespace lb_library
+{
+  class BGModel
+  {
+  public:
+
+    BGModel(int width, int height);
+    virtual ~BGModel();
+
+    void InitModel(IplImage* image);
+    void UpdateModel(IplImage* image);
+  
+    virtual void setBGModelParameter(int id, int value) {};
+
+    virtual IplImage* GetSrc();
+    virtual IplImage* GetFG();
+    virtual IplImage* GetBG();
+
+  protected:
+  
+    IplImage* m_SrcImage;
+    IplImage* m_BGImage;
+    IplImage* m_FGImage;
+
+    const int m_width;
+    const int m_height;
+  
+    virtual void Init() = 0;
+    virtual void Update() = 0;
+  };
+}
+
+#endif
diff --git a/package_bgs/lb/BGModelFuzzyGauss.cpp b/package_bgs/lb/BGModelFuzzyGauss.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8706b1376e76f635eae77759b2ab59c63808d152
--- /dev/null
+++ b/package_bgs/lb/BGModelFuzzyGauss.cpp
@@ -0,0 +1,210 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelFuzzyGauss.cpp
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BGModelFuzzyGauss.h"
+
+namespace lb_library
+{
+  namespace FuzzyGaussian
+  {
+    BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width,height)
+    {
+      m_alphamax = ALPHAFUZZYGAUSS;
+      m_threshold = THRESHOLDFUZZYGAUSS * THRESHOLDFUZZYGAUSS;
+      m_threshBG = THRESHOLDBG;
+      m_noise = NOISEFUZZYGAUSS;
+
+      m_pMu = new DBLRGB[m_width * m_height];
+      m_pVar = new DBLRGB[m_width * m_height];
+
+      DBLRGB *pMu = m_pMu;
+      DBLRGB *pVar = m_pVar;
+
+      for(int k = 0; k < (m_width * m_height); k++)
+      {
+        pMu->Red = 0.0;
+        pMu->Green = 0.0;
+        pMu->Blue = 0.0;
+
+        pVar->Red = m_noise;
+        pVar->Green = m_noise;
+        pVar->Blue = m_noise;
+
+        pMu++;
+        pVar++;
+      }
+    }
+
+    BGModelFuzzyGauss::~BGModelFuzzyGauss()
+    {
+      delete [] m_pMu;
+      delete [] m_pVar;
+    }
+
+    void BGModelFuzzyGauss::setBGModelParameter(int id, int value)
+    {
+      double dvalue = (double)value/255.0;
+
+      switch(id)
+      {
+      case 0:
+        m_threshold = 100.0*dvalue*dvalue;
+        break;
+
+      case 1:
+        m_threshBG = dvalue;
+        break;
+
+      case 2:
+        m_alphamax = dvalue*dvalue*dvalue;
+        break;
+
+      case 3:
+        m_noise = 100.0*dvalue;
+        break;
+      }
+
+      return;
+    }
+
+    void BGModelFuzzyGauss::Init()
+    {
+      DBLRGB *pMu = m_pMu;
+      DBLRGB *pVar = m_pVar;
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+
+      for(int i = 0; i < m_height; i++)
+      {
+        for(int j = 0; j < m_width; j++)
+        {
+          pMu->Red = prgbSrc[i][j].Red;
+          pMu->Green = prgbSrc[i][j].Green;
+          pMu->Blue = prgbSrc[i][j].Blue;
+
+          pVar->Red = m_noise;
+          pVar->Green = m_noise;
+          pVar->Blue = m_noise;
+
+          pMu++;
+          pVar++;
+        }
+      }
+
+      return;
+    }
+
+    void BGModelFuzzyGauss::Update()
+    {
+      DBLRGB *pMu = m_pMu;
+      DBLRGB *pVar = m_pVar;
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+      Image<BYTERGB> prgbBG(m_BGImage);
+      Image<BYTERGB> prgbFG(m_FGImage);
+
+      for(int i = 0; i < m_height; i++)
+      {
+        for(int j = 0; j < m_width; j++)
+        {
+          double srcR = (double) prgbSrc[i][j].Red;
+          double srcG = (double) prgbSrc[i][j].Green;
+          double srcB = (double) prgbSrc[i][j].Blue;
+
+          // Fuzzy background subtraction (Mahalanobis distance)
+
+          double dr = srcR - pMu->Red;
+          double dg = srcG - pMu->Green;
+          double db = srcB - pMu->Blue;
+
+          double d2 = dr*dr/pVar->Red + dg*dg/pVar->Green + db*db/pVar->Blue;
+
+          double fuzzyBG = 1.0;
+
+          if(d2 < m_threshold)
+            fuzzyBG = d2/m_threshold;
+
+          // Fuzzy running average
+
+          double alpha = m_alphamax*exp(FUZZYEXP*fuzzyBG);
+
+          if(dr*dr > DBL_MIN)
+            pMu->Red += alpha*dr;
+
+          if(dg*dg > DBL_MIN)
+            pMu->Green += alpha*dg;
+
+          if(db*db > DBL_MIN)
+            pMu->Blue += alpha*db;
+
+          double d;
+
+          d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red;
+          if(d*d > DBL_MIN)
+            pVar->Red += alpha*d;
+
+          d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green;
+          if(d*d > DBL_MIN)
+            pVar->Green += alpha*d;
+
+          d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue;
+          if(d*d > DBL_MIN)
+            pVar->Blue += alpha*d;
+
+          pVar->Red = (std::max)(pVar->Red,m_noise);
+          pVar->Green = (std::max)(pVar->Green,m_noise);
+          pVar->Blue = (std::max)(pVar->Blue,m_noise);
+
+          // Set foreground and background
+
+          if(fuzzyBG >= m_threshBG)
+            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;
+          else
+            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;
+
+          prgbBG[i][j].Red = (unsigned char)pMu->Red;			
+          prgbBG[i][j].Green = (unsigned char)pMu->Green;			
+          prgbBG[i][j].Blue = (unsigned char)pMu->Blue;
+
+          pMu++;
+          pVar++;
+        }
+      }
+
+      return;
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/lb/BGModelFuzzyGauss.h b/package_bgs/lb/BGModelFuzzyGauss.h
new file mode 100644
index 0000000000000000000000000000000000000000..033eaf318d260cd8bc1c2c459cb3314886c36d8e
--- /dev/null
+++ b/package_bgs/lb/BGModelFuzzyGauss.h
@@ -0,0 +1,75 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelFuzzyGauss.h
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef BGMODELFUZZYGAUSS_H
+#define BGMODELFUZZYGAUSS_H
+
+#include "BGModel.h"
+
+namespace lb_library
+{
+  namespace FuzzyGaussian
+  {
+    const float ALPHAFUZZYGAUSS = 0.02;
+    const float THRESHOLDFUZZYGAUSS = 3.5;
+    const float THRESHOLDBG = 0.5;
+    const float NOISEFUZZYGAUSS = 50.0;
+    const float FUZZYEXP = -5.0;
+
+    class BGModelFuzzyGauss : public BGModel
+    {
+    public:
+      BGModelFuzzyGauss(int width, int height);
+      ~BGModelFuzzyGauss();
+
+      void setBGModelParameter(int id, int value);
+
+    protected:
+      double m_alphamax;
+      double m_threshold;
+      double m_threshBG;
+      double m_noise;
+
+      DBLRGB* m_pMu;
+      DBLRGB* m_pVar;
+
+      void Init();
+      void Update();
+    };
+  }
+}
+
+#endif
diff --git a/package_bgs/lb/BGModelFuzzySom.cpp b/package_bgs/lb/BGModelFuzzySom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..189cb1aa3cd0faa138e70a197dafe6283eda0656
--- /dev/null
+++ b/package_bgs/lb/BGModelFuzzySom.cpp
@@ -0,0 +1,298 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelFuzzySom.cpp
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BGModelFuzzySom.h"
+
+namespace lb_library
+{
+  namespace FuzzyAdaptiveSOM
+  {
+    BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width,height)
+    {
+      m_offset = (KERNEL - 1)/2;
+
+      if(SPAN_NEIGHBORS)
+        m_pad = 0;	
+      else
+        m_pad = m_offset;
+
+      // SOM models
+
+      m_widthSOM = m_width*M + 2*m_offset + (m_width-1)*m_pad;
+      m_heightSOM = m_height*N + 2*m_offset + (m_height-1)*m_pad;
+
+      m_ppSOM = new DBLRGB*[m_heightSOM];	
+      for(int n = 0; n < m_heightSOM; n++)
+        m_ppSOM[n] = new DBLRGB[m_widthSOM];
+
+      for(int j = 0; j < m_heightSOM; j++)
+      {
+        for(int i = 0; i < m_widthSOM; i++)
+        {
+          m_ppSOM[j][i].Red = 0.0;
+          m_ppSOM[j][i].Green = 0.0;
+          m_ppSOM[j][i].Blue = 0.0;
+        }
+      }
+
+      // Create weights
+
+      m_ppW = new double*[KERNEL];
+      for(int n = 0; n < KERNEL; n++)
+        m_ppW[n] = new double[KERNEL];
+
+      // Construct Gaussian kernel using Pascal's triangle
+
+      int cM;
+      int cN;
+      m_Wmax = DBL_MIN;
+
+      cN = 1;
+      for(int j = 0; j < KERNEL; j++)
+      {
+        cM = 1;		
+
+        for(int i = 0; i < KERNEL; i++)
+        {
+          m_ppW[j][i] = cN*cM;
+
+          if(m_ppW[j][i] > m_Wmax)
+            m_Wmax = m_ppW[j][i];
+
+          cM = cM * (KERNEL - 1 - i) / (i + 1);
+        }
+
+        cN = cN * (KERNEL - 1 - j) / (j + 1);
+      }
+
+      // Parameters
+
+      m_epsilon1 = EPS1*EPS1;
+      m_epsilon2 = EPS2*EPS2;
+
+      m_alpha1 = C1/m_Wmax;
+      m_alpha2 = C2/m_Wmax;
+
+      m_K = 0;
+      m_TSteps = TRAINING_STEPS;
+    }
+
+    BGModelFuzzySom::~BGModelFuzzySom()
+    {
+      for(int n = 0; n < m_heightSOM; n++)
+        delete [] m_ppSOM[n];
+
+      delete [] m_ppSOM;
+
+      for(int n = 0; n < KERNEL; n++)
+        delete [] m_ppW[n];
+
+      delete [] m_ppW;
+    }
+
+    void BGModelFuzzySom::setBGModelParameter(int id, int value)
+    {
+      double dvalue = (double)value/255.0;
+
+      switch(id)
+      {
+      case 0:
+        m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+        break;
+
+      case 1:
+        m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+        break;
+
+      case 2:
+        m_alpha2 = dvalue*dvalue*dvalue/m_Wmax;
+        break;
+
+      case 3:
+        m_alpha1 = dvalue*dvalue*dvalue/m_Wmax;
+        break;
+
+      case 5:
+        m_TSteps = (int)(255.0*dvalue);
+        break;
+      }
+
+      return;
+    }
+
+    void BGModelFuzzySom::Init()
+    {
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+
+      for(int j = 0; j < m_height; j++)
+      {
+        int jj = m_offset + j*(N + m_pad);
+
+        for(int i = 0; i < m_width; i++)
+        {
+          int ii = m_offset + i*(M + m_pad);		
+
+          for(int l = 0; l < N; l++)
+          {
+            for(int k = 0; k < M; k++)
+            {
+              m_ppSOM[jj+l][ii+k].Red = (double)prgbSrc[j][i].Red;
+              m_ppSOM[jj+l][ii+k].Green = (double)prgbSrc[j][i].Green;
+              m_ppSOM[jj+l][ii+k].Blue = (double)prgbSrc[j][i].Blue;
+            }
+          }
+        }
+      }
+
+      m_K = 0;
+
+      return;
+    }
+
+    void BGModelFuzzySom::Update()
+    {
+      double alpha,a;
+      double epsilon;
+
+      // calibration phase
+      if(m_K <= m_TSteps)
+      {
+        epsilon = m_epsilon1;
+        alpha = (m_alpha1 - m_K * (m_alpha1 - m_alpha2) / m_TSteps);
+        m_K++;
+      }
+      else // online phase
+      {
+        epsilon = m_epsilon2;
+        alpha = m_alpha2;
+      }
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+      Image<BYTERGB> prgbBG(m_BGImage);
+      Image<BYTERGB> prgbFG(m_FGImage);
+
+      for(int j = 0; j < m_height; j++)
+      {
+        int jj = m_offset + j*(N + m_pad);
+
+        for(int i = 0; i < m_width; i++)
+        {
+          int ii = m_offset + i*(M + m_pad);
+
+          double srcR = (double)prgbSrc[j][i].Red;
+          double srcG = (double)prgbSrc[j][i].Green;
+          double srcB = (double)prgbSrc[j][i].Blue;
+
+          // Find BMU
+
+          double d2min = DBL_MAX;
+          int iiHit = ii;
+          int jjHit = jj;
+
+          for(int l = 0; l < N; l++)
+          {
+            for(int k = 0; k < M; k++)
+            {
+              double dr = srcR - m_ppSOM[jj+l][ii+k].Red;
+              double dg = srcG - m_ppSOM[jj+l][ii+k].Green;
+              double db = srcB - m_ppSOM[jj+l][ii+k].Blue;
+
+              double d2 = dr*dr + dg*dg + db*db;
+
+              if(d2 < d2min)
+              {
+                d2min = d2;
+                iiHit = ii + k;
+                jjHit = jj + l;
+              }
+            }
+          }
+
+          double fuzzyBG = 1.0;
+
+          if(d2min < epsilon)
+            fuzzyBG = d2min/epsilon;
+
+          // Update SOM
+
+          double alphamax = alpha*exp(FUZZYEXP*fuzzyBG);
+
+          for(int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++)
+          {
+            for(int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++)
+            {
+              a = alphamax * m_ppW[l - jjHit + m_offset][k - iiHit + m_offset];
+
+              // speed hack.. avoid very small increment values. abs() is sloooow.
+
+              double d;
+
+              d = srcR - m_ppSOM[l][k].Red;
+              if(d*d > DBL_MIN)
+                m_ppSOM[l][k].Red += a*d;
+
+              d = srcG - m_ppSOM[l][k].Green;
+              if(d*d > DBL_MIN)
+                m_ppSOM[l][k].Green += a*d;
+
+              d = srcB - m_ppSOM[l][k].Blue;
+              if(d*d > DBL_MIN)
+                m_ppSOM[l][k].Blue += a*d;
+            }
+          }
+
+          if(fuzzyBG >= FUZZYTHRESH)
+          {
+            // Set foreground image
+            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255;
+          }
+          else
+          {
+            // Set background image
+            prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red;
+            prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green;
+            prgbBG[j][i].Blue =  m_ppSOM[jjHit][iiHit].Blue;
+
+            // Set foreground image
+            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0;
+          }
+        }
+      }
+
+      return;
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/lb/BGModelFuzzySom.h b/package_bgs/lb/BGModelFuzzySom.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f21d3e01368863f6fa2188117b7527a520f82c4
--- /dev/null
+++ b/package_bgs/lb/BGModelFuzzySom.h
@@ -0,0 +1,95 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelFuzzySom.h
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef BGMODELFUZZYSOM_H
+#define BGMODELFUZZYSOM_H
+
+#include "BGModel.h"
+
+namespace lb_library
+{
+  namespace FuzzyAdaptiveSOM
+  {
+    // SOM parameters
+
+    const int M = 3;				// width SOM (per pixel)
+    const int N = 3;				// height SOM (per pixel)
+    const int KERNEL = 3; 	// size Gaussian kernel 
+
+    const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels			// 
+    const int TRAINING_STEPS = 100;			// number of training steps
+
+    const double EPS1 = 100.0; // model match distance during training
+    const double EPS2 = 20.0;  // model match distance
+    const double C1 = 1.0;     // learning rate during training
+    const double C2 = 0.05;    // learning rate
+
+    const double FUZZYEXP = -5.0;
+    const double FUZZYTHRESH = 0.8;
+
+    class BGModelFuzzySom : public BGModel
+    {
+    public:
+      BGModelFuzzySom(int width, int height);
+      ~BGModelFuzzySom();
+
+      void setBGModelParameter(int id, int value);
+
+    protected:
+      int m_widthSOM;
+      int m_heightSOM;
+      int m_offset;
+      int m_pad;
+      int m_K;
+      int m_TSteps;
+
+      double m_Wmax;
+
+      double m_epsilon1;
+      double m_epsilon2;
+      double m_alpha1;
+      double m_alpha2;
+
+      DBLRGB** m_ppSOM;					// SOM grid
+      double** m_ppW;						// Weights 
+
+      void Init();
+      void Update();
+    };
+  }
+}
+
+#endif
diff --git a/package_bgs/lb/BGModelGauss.cpp b/package_bgs/lb/BGModelGauss.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6892d13b9b9820f8f61734b2bde3d37ce8c74c5d
--- /dev/null
+++ b/package_bgs/lb/BGModelGauss.cpp
@@ -0,0 +1,200 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelGauss.cpp
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BGModelGauss.h"
+
+namespace lb_library
+{
+  namespace SimpleGaussian
+  {
+    BGModelGauss::BGModelGauss(int width, int height) : BGModel(width,height)
+    {
+      m_alpha = ALPHAGAUSS;
+      m_threshold = THRESHGAUSS*THRESHGAUSS;
+      m_noise = NOISEGAUSS;
+
+      m_pMu = new DBLRGB[m_width * m_height];
+      m_pVar = new DBLRGB[m_width * m_height];
+
+      DBLRGB *pMu = m_pMu;
+      DBLRGB *pVar = m_pVar;
+
+      for(int k = 0; k < (m_width * m_height); k++)
+      {
+        pMu->Red = 0.0;
+        pMu->Green = 0.0;
+        pMu->Blue = 0.0;
+
+        pVar->Red = m_noise;
+        pVar->Green = m_noise;
+        pVar->Blue = m_noise;
+
+        pMu++;
+        pVar++;
+      }
+    }
+
+    BGModelGauss::~BGModelGauss()
+    {
+      delete [] m_pMu;
+      delete [] m_pVar;
+    }
+
+    void BGModelGauss::setBGModelParameter(int id, int value)
+    {
+      double dvalue = (double)value/255.0;
+
+      switch(id)
+      {
+      case 0:
+        m_threshold = 100.0*dvalue*dvalue;
+        break;
+
+      case 1:
+        m_noise = 100.0*dvalue;
+        break;
+
+      case 2: 
+        m_alpha = dvalue*dvalue*dvalue;
+        break;
+      }
+
+      return;
+    }
+
+    void BGModelGauss::Init()
+    {
+      DBLRGB *pMu = m_pMu;
+      DBLRGB *pVar = m_pVar;
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+
+      for(int i = 0; i < m_height; i++)
+      {
+        for(int j = 0; j < m_width; j++)
+        {
+          pMu->Red = prgbSrc[i][j].Red;
+          pMu->Green = prgbSrc[i][j].Green;
+          pMu->Blue = prgbSrc[i][j].Blue;
+
+          pVar->Red = m_noise;
+          pVar->Green = m_noise;
+          pVar->Blue = m_noise;
+
+          pMu++;
+          pVar++;
+        }
+      }
+
+      return;
+    }
+
+    void BGModelGauss::Update()
+    {
+      DBLRGB *pMu = m_pMu;
+      DBLRGB *pVar = m_pVar;
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+      Image<BYTERGB> prgbBG(m_BGImage);
+      Image<BYTERGB> prgbFG(m_FGImage);
+
+      for(int i = 0; i < m_height; i++)
+      {
+        for(int j = 0; j < m_width; j++)
+        {
+          double srcR = (double) prgbSrc[i][j].Red;
+          double srcG = (double) prgbSrc[i][j].Green;
+          double srcB = (double) prgbSrc[i][j].Blue;
+
+          // Mahalanobis distance 
+
+          double dr = srcR - pMu->Red;
+          double dg = srcG - pMu->Green;
+          double db = srcB - pMu->Blue;
+
+          double d2 = dr*dr/pVar->Red + dg*dg/pVar->Green + db*db/pVar->Blue;
+
+          // Classify
+
+          if(d2 < m_threshold)
+            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;		
+          else
+            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;		
+
+          // Update parameters
+
+          if(dr*dr > DBL_MIN)
+            pMu->Red += m_alpha*dr;
+
+          if(dg*dg > DBL_MIN)
+            pMu->Green += m_alpha*dg;
+
+          if(db*db > DBL_MIN)
+            pMu->Blue += m_alpha*db;
+
+          double d;
+
+          d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red;
+          if(d*d > DBL_MIN)
+            pVar->Red += m_alpha*d;
+
+          d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green;
+          if(d*d > DBL_MIN)
+            pVar->Green += m_alpha*d;
+
+          d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue;
+          if(d*d > DBL_MIN)
+            pVar->Blue += m_alpha*d;
+
+          pVar->Red = (std::min)(pVar->Red,m_noise);
+          pVar->Green = (std::min)(pVar->Green,m_noise);
+          pVar->Blue = (std::min)(pVar->Blue,m_noise);
+
+          // Set background
+
+          prgbBG[i][j].Red = (unsigned char)pMu->Red;			
+          prgbBG[i][j].Green = (unsigned char)pMu->Green;			
+          prgbBG[i][j].Blue = (unsigned char)pMu->Blue;
+
+          pMu++;
+          pVar++;
+        }
+      }
+
+      return;
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/lb/BGModelGauss.h b/package_bgs/lb/BGModelGauss.h
new file mode 100644
index 0000000000000000000000000000000000000000..d36a716ab4094acd9ea431b6c834dc563ecfacae
--- /dev/null
+++ b/package_bgs/lb/BGModelGauss.h
@@ -0,0 +1,73 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelGauss.h
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef BGMODELGAUSS_H
+#define BGMODELGAUSS_H
+
+#include "BGModel.h"
+
+namespace lb_library
+{
+  namespace SimpleGaussian
+  {
+    // Parameters
+    const double THRESHGAUSS = 2.5;   // Threshold
+    const double ALPHAGAUSS = 0.0001; // Learning rate
+    const double NOISEGAUSS = 50.0;   // Minimum variance (noise)
+
+    class BGModelGauss : public BGModel
+    {
+    public:
+      BGModelGauss(int width, int height);
+      ~BGModelGauss();
+
+      void setBGModelParameter(int id, int value);
+
+    protected:
+      double m_alpha;
+      double m_threshold;
+      double m_noise;
+
+      DBLRGB* m_pMu;
+      DBLRGB* m_pVar;
+
+      void Init();
+      void Update();
+    };
+  }
+}
+
+#endif
diff --git a/package_bgs/lb/BGModelMog.cpp b/package_bgs/lb/BGModelMog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..df6986c90327115f7fb56d5066f976b7e1f8b3f7
--- /dev/null
+++ b/package_bgs/lb/BGModelMog.cpp
@@ -0,0 +1,309 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelMog.cpp
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BGModelMog.h"
+
+namespace lb_library
+{
+  namespace MixtureOfGaussians
+  {
+    BGModelMog::BGModelMog(int width, int height) : BGModel(width, height)
+    {
+      m_alpha = LEARNINGRATEMOG;
+      m_threshold = THRESHOLDMOG*THRESHOLDMOG;
+      m_noise = INITIALVARMOG;
+
+      m_T = BGTHRESHOLDMOG;
+
+      m_pMOG = new MOGDATA[NUMBERGAUSSIANS*m_width*m_height];
+      m_pK = new int[m_width*m_height];
+
+      MOGDATA *pMOG = m_pMOG;
+      int *pK = m_pK;
+
+      for(int i = 0; i < (m_width * m_height); i++)
+      {
+        for(int k = 0; k < NUMBERGAUSSIANS; k++)
+        {
+          pMOG->mu.Red = 0.0;
+          pMOG->mu.Green = 0.0;
+          pMOG->mu.Blue = 0.0;
+
+          pMOG->var.Red = 0.0;
+          pMOG->var.Green = 0.0;
+          pMOG->var.Blue = 0.0;
+
+          pMOG->w = 0.0;
+          pMOG->sortKey = 0.0;
+
+          pMOG++;
+        }
+
+        pK[i] = 0; 
+      }
+    }
+
+    BGModelMog::~BGModelMog()
+    {
+      delete [] m_pMOG;
+      delete [] m_pK;
+    }
+
+    void BGModelMog::setBGModelParameter(int id, int value)
+    {
+      double dvalue = (double)value/255.0;
+
+      switch(id)
+      {
+      case 0:
+        m_threshold = 100.0*dvalue*dvalue;
+        break;
+
+      case 1: 
+        m_T = dvalue;
+        break;
+
+      case 2:
+        m_alpha = dvalue*dvalue*dvalue;
+        break;
+
+      case 3: 
+        m_noise = 100.0*dvalue;;
+        break;
+      }
+
+      return;
+    }
+
+    void BGModelMog::Init()
+    {
+      MOGDATA *pMOG = m_pMOG;
+      int *pK = m_pK;
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+
+      int n = 0;
+      for(int i = 0; i < m_height; i++)
+      {
+        for(int j = 0; j < m_width; j++)
+        {
+          pMOG[0].mu.Red = prgbSrc[i][j].Red;
+          pMOG[0].mu.Green = prgbSrc[i][j].Green;
+          pMOG[0].mu.Blue = prgbSrc[i][j].Blue;
+
+          pMOG[0].var.Red = m_noise;
+          pMOG[0].var.Green = m_noise;
+          pMOG[0].var.Blue = m_noise;
+
+          pMOG[0].w = 1.0;
+          pMOG[0].sortKey = pMOG[0].w/sqrt(pMOG[0].var.Red+pMOG[0].var.Green+pMOG[0].var.Blue);
+
+          pK[n] = 1;
+          n++;
+
+          pMOG += NUMBERGAUSSIANS;
+        }
+      }
+
+      return;
+    }
+
+    void BGModelMog::Update()
+    {
+      int kBG;
+
+      MOGDATA *pMOG = m_pMOG;
+      int *pK = m_pK;
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+      Image<BYTERGB> prgbBG(m_BGImage);
+      Image<BYTERGB> prgbFG(m_FGImage);
+
+      int n = 0;
+      for(int i = 0; i < m_height; i++)
+      {
+        for(int j = 0; j < m_width; j++)
+        {
+          double srcR = (double) prgbSrc[i][j].Red;
+          double srcG = (double) prgbSrc[i][j].Green;
+          double srcB = (double) prgbSrc[i][j].Blue;
+
+          // Find matching distribution
+
+          int kHit = -1;
+
+          for(int k = 0; k < pK[n]; k++)
+          {
+            // Mahalanobis distance
+            double dr = srcR - pMOG[k].mu.Red;
+            double dg = srcG - pMOG[k].mu.Green;
+            double db = srcB - pMOG[k].mu.Blue;
+            double d2 = dr*dr/pMOG[k].var.Red + dg*dg/pMOG[k].var.Green + db*db/pMOG[k].var.Blue;
+
+            if(d2 < m_threshold)
+            {
+              kHit = k;
+              break;
+            }
+          }
+
+          // Adjust parameters
+
+          // matching distribution found
+          if(kHit != -1)
+          {
+            for(int k = 0; k < pK[n]; k++)
+            {
+              if(k == kHit)
+              {
+                pMOG[k].w = pMOG[k].w + m_alpha*(1.0f - pMOG[k].w);
+
+                double d;
+
+                d = srcR - pMOG[k].mu.Red;
+                if(d*d > DBL_MIN)
+                  pMOG[k].mu.Red += m_alpha*d;
+
+                d = srcG - pMOG[k].mu.Green;
+                if(d*d > DBL_MIN)
+                  pMOG[k].mu.Green += m_alpha*d;
+
+                d = srcB - pMOG[k].mu.Blue;
+                if(d*d > DBL_MIN)
+                  pMOG[k].mu.Blue += m_alpha*d;
+
+                d = (srcR - pMOG[k].mu.Red)*(srcR - pMOG[k].mu.Red) - pMOG[k].var.Red;
+                if(d*d > DBL_MIN)
+                  pMOG[k].var.Red += m_alpha*d;
+
+                d = (srcG - pMOG[k].mu.Green)*(srcG - pMOG[k].mu.Green) - pMOG[k].var.Green;
+                if(d*d > DBL_MIN)
+                  pMOG[k].var.Green += m_alpha*d;
+
+                d = (srcB - pMOG[k].mu.Blue)*(srcB - pMOG[k].mu.Blue) - pMOG[k].var.Blue;
+                if(d*d > DBL_MIN)
+                  pMOG[k].var.Blue += m_alpha*d;
+
+                pMOG[k].var.Red = (std::max)(pMOG[k].var.Red,m_noise);
+                pMOG[k].var.Green = (std::max)(pMOG[k].var.Green,m_noise);
+                pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue,m_noise);
+              }
+              else
+                pMOG[k].w = (1.0 - m_alpha)*pMOG[k].w;
+            }
+          }
+          // no match found... create new one
+          else
+          {
+            if(pK[n] < NUMBERGAUSSIANS)
+              pK[n]++;
+
+            kHit = pK[n] - 1;
+
+            if(pK[n] == 1)
+              pMOG[kHit].w = 1.0;
+            else
+              pMOG[kHit].w = LEARNINGRATEMOG;
+
+            pMOG[kHit].mu.Red = srcR;
+            pMOG[kHit].mu.Green = srcG;
+            pMOG[kHit].mu.Blue = srcB;
+
+            pMOG[kHit].var.Red = m_noise;
+            pMOG[kHit].var.Green = m_noise;
+            pMOG[kHit].var.Blue = m_noise;
+          }
+
+          // Normalize weights
+
+          double wsum = 0.0;
+
+          for(int k = 0; k < pK[n]; k++) 
+            wsum += pMOG[k].w;
+
+          double wfactor = 1.0/wsum;
+
+          for(int k = 0; k < pK[n]; k++)
+          {
+            pMOG[k].w *= wfactor;
+            pMOG[k].sortKey = pMOG[k].w/sqrt(pMOG[k].var.Red+pMOG[k].var.Green+pMOG[k].var.Blue);
+          }
+
+          // Sort distributions
+
+          for (int k = 0; k < kHit; k++)
+          {
+            if(pMOG[kHit].sortKey > pMOG[k].sortKey)
+            {
+              std::swap(pMOG[kHit],pMOG[k]);
+              break;
+            }
+          }
+
+          // Determine background distributions
+
+          wsum = 0.0;
+
+          for(int k = 0; k < pK[n]; k++)
+          {
+            wsum += pMOG[k].w;
+
+            if(wsum > m_T)
+            {
+              kBG = k;
+              break;
+            }
+          }
+
+          if(kHit > kBG)
+            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255;			
+          else
+            prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0;			
+
+          prgbBG[i][j].Red = (unsigned char)pMOG[0].mu.Red;
+          prgbBG[i][j].Green = (unsigned char)pMOG[0].mu.Green;
+          prgbBG[i][j].Blue = (unsigned char)pMOG[0].mu.Blue;
+
+          pMOG += NUMBERGAUSSIANS;
+
+          n++;
+        }
+      }
+
+      return;
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/lb/BGModelMog.h b/package_bgs/lb/BGModelMog.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4e51a4447722bb0d8719297e1bd2e6269a53968
--- /dev/null
+++ b/package_bgs/lb/BGModelMog.h
@@ -0,0 +1,83 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelMog.h
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef BGMODELMOGRGB_H
+#define BGMODELMOGRGB_H
+
+#include "BGModel.h"
+
+namespace lb_library
+{
+  namespace MixtureOfGaussians
+  {
+    const unsigned int NUMBERGAUSSIANS = 3;
+    const float LEARNINGRATEMOG = 0.001f;
+    const float THRESHOLDMOG = 2.5f;
+    const float BGTHRESHOLDMOG = 0.5f;
+    const float INITIALVARMOG = 50.0f;
+
+    typedef struct tagMOGDATA
+    {
+      DBLRGB mu;
+      DBLRGB var;
+      double w;
+      double sortKey;
+    } MOGDATA;
+
+    class BGModelMog : public BGModel
+    {
+    public:
+      BGModelMog(int width, int height);
+      ~BGModelMog();
+
+      void setBGModelParameter(int id, int value);
+
+    protected:
+      double m_alpha;
+      double m_threshold;
+      double m_noise;
+      double m_T;
+
+      MOGDATA* m_pMOG;
+      int* m_pK;				// number of distributions per pixel
+
+      void Init();
+      void Update();
+    };
+  }
+}
+
+#endif
diff --git a/package_bgs/lb/BGModelSom.cpp b/package_bgs/lb/BGModelSom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..256d4855f62d71aab321be466098f754fa7597ed
--- /dev/null
+++ b/package_bgs/lb/BGModelSom.cpp
@@ -0,0 +1,291 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelSom.cpp
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "BGModelSom.h"
+
+namespace lb_library
+{
+  namespace AdaptiveSOM
+  {
+    BGModelSom::BGModelSom(int width, int height) : BGModel(width,height)
+    {
+      m_offset = (KERNEL - 1)/2;
+
+      if(SPAN_NEIGHBORS)
+        m_pad = 0;	
+      else
+        m_pad = m_offset;
+
+      // SOM models
+
+      m_widthSOM = m_width*M + 2*m_offset + (m_width-1)*m_pad;
+      m_heightSOM = m_height*N + 2*m_offset + (m_height-1)*m_pad;
+
+      m_ppSOM = new DBLRGB*[m_heightSOM];	
+      for(int n = 0; n < m_heightSOM; n++)
+        m_ppSOM[n] = new DBLRGB[m_widthSOM];
+
+      for(int j = 0; j < m_heightSOM; j++)
+      {
+        for(int i = 0; i < m_widthSOM; i++)
+        {							
+          m_ppSOM[j][i].Red = 0.0;
+          m_ppSOM[j][i].Green = 0.0;
+          m_ppSOM[j][i].Blue = 0.0;
+        }
+      }
+
+      // Create weights
+
+      m_ppW = new double*[KERNEL];
+      for(int n = 0; n < KERNEL; n++)
+        m_ppW[n] = new double[KERNEL];
+
+      // Construct Gaussian kernel using Pascal's triangle
+
+      int cM;
+      int cN;
+      m_Wmax = DBL_MIN;
+
+      cN = 1;
+      for(int j = 0; j < KERNEL; j++)
+      {
+        cM = 1;		
+
+        for(int i = 0; i < KERNEL; i++)
+        {
+          m_ppW[j][i] = cN*cM;
+
+          if(m_ppW[j][i] > m_Wmax)
+            m_Wmax = m_ppW[j][i]; 
+
+          cM = cM * (KERNEL - 1 - i) / (i + 1);
+        }
+
+        cN = cN * (KERNEL - 1 - j) / (j + 1);
+      }
+
+      // Parameters
+
+      m_epsilon1 = EPS1*EPS1;
+      m_epsilon2 = EPS2*EPS2;
+
+      m_alpha1 = C1/m_Wmax;
+      m_alpha2 = C2/m_Wmax;
+
+      m_K = 0;
+      m_TSteps = TRAINING_STEPS;
+    }
+
+    BGModelSom::~BGModelSom()
+    {
+      for(int n = 0; n < m_heightSOM; n++)
+        delete [] m_ppSOM[n];
+
+      delete [] m_ppSOM;
+
+      for(int n = 0; n < KERNEL; n++)
+        delete [] m_ppW[n];
+
+      delete [] m_ppW;
+    }
+
+    void BGModelSom::setBGModelParameter(int id, int value)
+    {
+      double dvalue = (double)value/255.0;
+
+      switch(id)
+      {
+      case 0:
+        m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+        break;
+
+      case 1:
+        m_epsilon1 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue;
+        break;
+
+      case 2:
+        m_alpha2 = dvalue*dvalue*dvalue/m_Wmax;
+        break;
+
+      case 3:
+        m_alpha1 = dvalue*dvalue*dvalue/m_Wmax;
+        break;
+
+      case 5:
+        m_TSteps = (int)(255.0*dvalue);
+        break;
+      }
+
+      return;
+    }
+
+    void BGModelSom::Init()
+    {
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+
+      for(int j = 0; j < m_height; j++)
+      {
+        int jj = m_offset + j*(N + m_pad);
+
+        for(int i = 0; i < m_width; i++)
+        {
+          int ii = m_offset + i*(M + m_pad);		
+
+          for(int l = 0; l < N; l++)
+          {
+            for(int k = 0; k < M; k++)
+            {
+              m_ppSOM[jj+l][ii+k].Red = (double)prgbSrc[j][i].Red;
+              m_ppSOM[jj+l][ii+k].Green = (double)prgbSrc[j][i].Green;
+              m_ppSOM[jj+l][ii+k].Blue = (double)prgbSrc[j][i].Blue;
+            }
+          }
+        }
+      }
+
+      m_K = 0;
+
+      return;
+    }
+
+    void BGModelSom::Update()
+    {
+      double alpha,a;
+      double epsilon;
+
+      // calibration phase
+      if(m_K <= m_TSteps)
+      {									
+        epsilon = m_epsilon1;
+        alpha = (m_alpha1-m_K*(m_alpha1-m_alpha2)/m_TSteps);
+        m_K++;
+      }
+      else // online phase
+      {														
+        epsilon = m_epsilon2;
+        alpha = m_alpha2;
+      }
+
+      Image<BYTERGB> prgbSrc(m_SrcImage);
+      Image<BYTERGB> prgbBG(m_BGImage);
+      Image<BYTERGB> prgbFG(m_FGImage);
+
+      for(int j = 0; j < m_height; j++)
+      {
+        int jj = m_offset + j*(N + m_pad);
+
+        for(int i = 0; i < m_width; i++)
+        {
+          int ii = m_offset + i*(M + m_pad);
+
+          double srcR = (double)prgbSrc[j][i].Red;
+          double srcG = (double)prgbSrc[j][i].Green;
+          double srcB = (double)prgbSrc[j][i].Blue;
+
+          // Find BMU
+
+          double d2min = DBL_MAX;
+          int iiHit = ii;
+          int jjHit = jj;
+
+          for(int l = 0; l < N; l++)
+          {
+            for(int k = 0; k < M; k++)
+            {
+              double dr = srcR - m_ppSOM[jj+l][ii+k].Red;
+              double dg = srcG - m_ppSOM[jj+l][ii+k].Green;
+              double db = srcB - m_ppSOM[jj+l][ii+k].Blue;
+
+              double d2 = dr*dr + dg*dg + db*db;
+
+              if(d2 < d2min)
+              {
+                d2min = d2;
+                iiHit = ii + k;
+                jjHit = jj + l;
+              }
+            }
+          }
+
+          // Update SOM
+
+          if(d2min <= epsilon) // matching model found 
+          {
+            for(int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++)
+            {
+              for(int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++)
+              {
+                a = alpha*m_ppW[l-jjHit+m_offset][k-iiHit+m_offset];
+
+                // speed hack.. avoid very small increment values. abs() is sloooow.
+
+                double d;
+
+                d = srcR - m_ppSOM[l][k].Red;
+                if(d*d > DBL_MIN)
+                  m_ppSOM[l][k].Red += a*d;
+
+                d = srcG - m_ppSOM[l][k].Green;
+                if(d*d > DBL_MIN)
+                  m_ppSOM[l][k].Green += a*d;
+
+                d = srcB - m_ppSOM[l][k].Blue;
+                if(d*d > DBL_MIN)
+                  m_ppSOM[l][k].Blue += a*d;
+              }
+            }
+
+            // Set background image
+            prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red;
+            prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green;
+            prgbBG[j][i].Blue =  m_ppSOM[jjHit][iiHit].Blue;
+
+            // Set foreground image
+            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0;
+          }
+          else
+          {
+            // Set foreground image
+            prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255;
+          }
+        }
+      }
+
+      return;
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/lb/BGModelSom.h b/package_bgs/lb/BGModelSom.h
new file mode 100644
index 0000000000000000000000000000000000000000..e95af11fffd5e97a18a040722d25c30cc9ec298d
--- /dev/null
+++ b/package_bgs/lb/BGModelSom.h
@@ -0,0 +1,92 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+BGModelSom.h
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef BGMODELSOM_H
+#define BGMODELSOM_H
+
+#include "BGModel.h"
+
+namespace lb_library
+{
+  namespace AdaptiveSOM
+  {
+    // SOM parameters
+
+    const int M = 3;				// width SOM (per pixel)
+    const int N = 3;				// height SOM (per pixel)
+    const int KERNEL = 3; 	// size Gaussian kernel 
+
+    const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels			// 
+    const int TRAINING_STEPS = 100;			// number of training steps
+
+    const float EPS1 = 100.0; // model match distance during training
+    const float EPS2 = 20.0;  // model match distance
+    const float C1 = 1.0;     // learning rate during training
+    const float C2 = 0.05;    // learning rate
+
+    class BGModelSom : public BGModel
+    {
+    public:
+      BGModelSom(int width, int height);
+      ~BGModelSom();
+
+      void setBGModelParameter(int id, int value);
+
+    protected:
+      int m_widthSOM;
+      int m_heightSOM;
+      int m_offset;
+      int m_pad;
+      int m_K;
+      int m_TSteps;
+
+      double m_Wmax;
+
+      double m_epsilon1;
+      double m_epsilon2;
+      double m_alpha1;
+      double m_alpha2;
+
+      DBLRGB** m_ppSOM;					// SOM grid
+      double** m_ppW;						// Weights 
+
+      void Init();
+      void Update();
+    };
+  }
+}
+
+#endif
diff --git a/package_bgs/lb/LBAdaptiveSOM.cpp b/package_bgs/lb/LBAdaptiveSOM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce06433cf8ab1547a053bbf0576f7c2c6026009f
--- /dev/null
+++ b/package_bgs/lb/LBAdaptiveSOM.cpp
@@ -0,0 +1,109 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "LBAdaptiveSOM.h"
+
+LBAdaptiveSOM::LBAdaptiveSOM() : firstTime(true), showOutput(true), 
+  sensitivity(75), trainingSensitivity(245), learningRate(62), trainingLearningRate(255), trainingSteps(55)
+{
+  std::cout << "LBAdaptiveSOM()" << std::endl;
+}
+
+LBAdaptiveSOM::~LBAdaptiveSOM()
+{
+  delete m_pBGModel;
+  std::cout << "~LBAdaptiveSOM()" << std::endl;
+}
+
+void LBAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+  
+  IplImage *frame = new IplImage(img_input);
+  
+  if(firstTime)
+  {
+    saveConfig();
+
+    int w = cvGetSize(frame).width;
+    int h = cvGetSize(frame).height;
+
+    m_pBGModel = new BGModelSom(w,h);
+    m_pBGModel->InitModel(frame);
+  }
+  
+  m_pBGModel->setBGModelParameter(0,sensitivity);
+  m_pBGModel->setBGModelParameter(1,trainingSensitivity);
+  m_pBGModel->setBGModelParameter(2,learningRate);
+  m_pBGModel->setBGModelParameter(3,trainingLearningRate);
+  m_pBGModel->setBGModelParameter(5,trainingSteps);
+
+  m_pBGModel->UpdateModel(frame);
+
+  img_foreground = cv::Mat(m_pBGModel->GetFG());
+  img_background = cv::Mat(m_pBGModel->GetBG());
+    
+  if(showOutput)
+  {
+    cv::imshow("SOM Mask", img_foreground);
+    cv::imshow("SOM Model", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+  
+  delete frame;
+  
+  firstTime = false;
+}
+
+//void LBAdaptiveSOM::finish(void)
+//{
+//  delete m_pBGModel;
+//}
+
+void LBAdaptiveSOM::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBAdaptiveSOM.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "sensitivity", sensitivity);
+  cvWriteInt(fs, "trainingSensitivity", trainingSensitivity);
+  cvWriteInt(fs, "learningRate", learningRate);
+  cvWriteInt(fs, "trainingLearningRate", trainingLearningRate);
+  cvWriteInt(fs, "trainingSteps", trainingSteps);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void LBAdaptiveSOM::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBAdaptiveSOM.xml", 0, CV_STORAGE_READ);
+  
+  sensitivity          = cvReadIntByName(fs, 0, "sensitivity", 75);
+  trainingSensitivity  = cvReadIntByName(fs, 0, "trainingSensitivity", 245);
+  learningRate         = cvReadIntByName(fs, 0, "learningRate", 62);
+  trainingLearningRate = cvReadIntByName(fs, 0, "trainingLearningRate", 255);
+  trainingSteps        = cvReadIntByName(fs, 0, "trainingSteps", 55);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/lb/LBAdaptiveSOM.h b/package_bgs/lb/LBAdaptiveSOM.h
new file mode 100644
index 0000000000000000000000000000000000000000..6e001dfcffc35cfbc609d7f0bb4905f4b2008852
--- /dev/null
+++ b/package_bgs/lb/LBAdaptiveSOM.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "BGModelSom.h"
+
+#include "../IBGS.h"
+
+using namespace lb_library;
+using namespace lb_library::AdaptiveSOM;
+
+class LBAdaptiveSOM : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+  
+  BGModel* m_pBGModel;
+  int sensitivity;
+  int trainingSensitivity;
+  int learningRate;
+  int trainingLearningRate;
+  int trainingSteps;
+
+  cv::Mat img_foreground;
+  cv::Mat img_background;
+
+public:
+  LBAdaptiveSOM();
+  ~LBAdaptiveSOM();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+  //void finish(void);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/lb/LBFuzzyAdaptiveSOM.cpp b/package_bgs/lb/LBFuzzyAdaptiveSOM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ef856028cbd063cda01e3aaacef7c702c9713d4
--- /dev/null
+++ b/package_bgs/lb/LBFuzzyAdaptiveSOM.cpp
@@ -0,0 +1,109 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "LBFuzzyAdaptiveSOM.h"
+
+LBFuzzyAdaptiveSOM::LBFuzzyAdaptiveSOM() : firstTime(true), showOutput(true), 
+  sensitivity(90), trainingSensitivity(240), learningRate(38), trainingLearningRate(255), trainingSteps(81)
+{
+  std::cout << "LBFuzzyAdaptiveSOM()" << std::endl;
+}
+
+LBFuzzyAdaptiveSOM::~LBFuzzyAdaptiveSOM()
+{
+  delete m_pBGModel;
+  std::cout << "~LBFuzzyAdaptiveSOM()" << std::endl;
+}
+
+void LBFuzzyAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+  
+  IplImage *frame = new IplImage(img_input);
+  
+  if(firstTime)
+  {
+    saveConfig();
+
+    int w = cvGetSize(frame).width;
+    int h = cvGetSize(frame).height;
+
+    m_pBGModel = new BGModelFuzzySom(w,h);
+    m_pBGModel->InitModel(frame);
+  }
+  
+  m_pBGModel->setBGModelParameter(0,sensitivity);
+  m_pBGModel->setBGModelParameter(1,trainingSensitivity);
+  m_pBGModel->setBGModelParameter(2,learningRate);
+  m_pBGModel->setBGModelParameter(3,trainingLearningRate);
+  m_pBGModel->setBGModelParameter(5,trainingSteps);
+
+  m_pBGModel->UpdateModel(frame);
+
+  img_foreground = cv::Mat(m_pBGModel->GetFG());
+  img_background = cv::Mat(m_pBGModel->GetBG());
+    
+  if(showOutput)
+  {
+    cv::imshow("FSOM Mask", img_foreground);
+    cv::imshow("FSOM Model", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+  
+  delete frame;
+  
+  firstTime = false;
+}
+
+//void LBFuzzyAdaptiveSOM::finish(void)
+//{
+//  //delete m_pBGModel;
+//}
+
+void LBFuzzyAdaptiveSOM::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyAdaptiveSOM.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "sensitivity", sensitivity);
+  cvWriteInt(fs, "trainingSensitivity", trainingSensitivity);
+  cvWriteInt(fs, "learningRate", learningRate);
+  cvWriteInt(fs, "trainingLearningRate", trainingLearningRate);
+  cvWriteInt(fs, "trainingSteps", trainingSteps);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void LBFuzzyAdaptiveSOM::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyAdaptiveSOM.xml", 0, CV_STORAGE_READ);
+  
+  sensitivity          = cvReadIntByName(fs, 0, "sensitivity", 90);
+  trainingSensitivity  = cvReadIntByName(fs, 0, "trainingSensitivity", 240);
+  learningRate         = cvReadIntByName(fs, 0, "learningRate", 38);
+  trainingLearningRate = cvReadIntByName(fs, 0, "trainingLearningRate", 255);
+  trainingSteps        = cvReadIntByName(fs, 0, "trainingSteps", 81);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/lb/LBFuzzyAdaptiveSOM.h b/package_bgs/lb/LBFuzzyAdaptiveSOM.h
new file mode 100644
index 0000000000000000000000000000000000000000..76dec2f87bd4679c690c5bb0d3be2f9e0640ad83
--- /dev/null
+++ b/package_bgs/lb/LBFuzzyAdaptiveSOM.h
@@ -0,0 +1,56 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "BGModelFuzzySom.h"
+
+#include "../IBGS.h"
+
+using namespace lb_library;
+using namespace lb_library::FuzzyAdaptiveSOM;
+
+class LBFuzzyAdaptiveSOM : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+  
+  BGModel* m_pBGModel;
+  int sensitivity;
+  int trainingSensitivity;
+  int learningRate;
+  int trainingLearningRate;
+  int trainingSteps;
+
+  cv::Mat img_foreground;
+  cv::Mat img_background;
+
+public:
+  LBFuzzyAdaptiveSOM();
+  ~LBFuzzyAdaptiveSOM();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+  //void finish(void);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/lb/LBFuzzyGaussian.cpp b/package_bgs/lb/LBFuzzyGaussian.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc257bf40325167efbe49220be9d08f9f745d4f7
--- /dev/null
+++ b/package_bgs/lb/LBFuzzyGaussian.cpp
@@ -0,0 +1,105 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "LBFuzzyGaussian.h"
+
+LBFuzzyGaussian::LBFuzzyGaussian() : firstTime(true), showOutput(true), sensitivity(72), bgThreshold(162), learningRate(49), noiseVariance(195)
+{
+  std::cout << "LBFuzzyGaussian()" << std::endl;
+}
+
+LBFuzzyGaussian::~LBFuzzyGaussian()
+{
+  delete m_pBGModel;
+  std::cout << "~LBFuzzyGaussian()" << std::endl;
+}
+
+void LBFuzzyGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+  
+  IplImage *frame = new IplImage(img_input);
+  
+  if(firstTime)
+  {
+    saveConfig();
+
+    int w = cvGetSize(frame).width;
+    int h = cvGetSize(frame).height;
+
+    m_pBGModel = new BGModelFuzzyGauss(w,h);
+    m_pBGModel->InitModel(frame);
+  }
+  
+  m_pBGModel->setBGModelParameter(0,sensitivity);
+  m_pBGModel->setBGModelParameter(1,bgThreshold);
+  m_pBGModel->setBGModelParameter(2,learningRate);
+  m_pBGModel->setBGModelParameter(3,noiseVariance);
+
+  m_pBGModel->UpdateModel(frame);
+
+  img_foreground = cv::Mat(m_pBGModel->GetFG());
+  img_background = cv::Mat(m_pBGModel->GetBG());
+    
+  if(showOutput)
+  {
+    cv::imshow("FG Mask", img_foreground);
+    cv::imshow("FG Model", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+  
+  delete frame;
+  
+  firstTime = false;
+}
+
+//void LBFuzzyGaussian::finish(void)
+//{
+//  delete m_pBGModel;
+//}
+
+void LBFuzzyGaussian::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyGaussian.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "sensitivity", sensitivity);
+  cvWriteInt(fs, "bgThreshold", bgThreshold);
+  cvWriteInt(fs, "learningRate", learningRate);
+  cvWriteInt(fs, "noiseVariance", noiseVariance);
+  
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void LBFuzzyGaussian::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyGaussian.xml", 0, CV_STORAGE_READ);
+  
+  sensitivity = cvReadIntByName(fs, 0, "sensitivity", 72);
+  bgThreshold = cvReadIntByName(fs, 0, "bgThreshold", 162);
+  learningRate = cvReadIntByName(fs, 0, "learningRate", 49);
+  noiseVariance = cvReadIntByName(fs, 0, "noiseVariance", 195);
+  
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/lb/LBFuzzyGaussian.h b/package_bgs/lb/LBFuzzyGaussian.h
new file mode 100644
index 0000000000000000000000000000000000000000..408c4a51d50ad36c0df49e092ea3f36d51ee2b6d
--- /dev/null
+++ b/package_bgs/lb/LBFuzzyGaussian.h
@@ -0,0 +1,55 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "BGModelFuzzyGauss.h"
+
+#include "../IBGS.h"
+
+using namespace lb_library;
+using namespace lb_library::FuzzyGaussian;
+
+class LBFuzzyGaussian : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+  
+  BGModel* m_pBGModel;
+  int sensitivity;
+  int bgThreshold;
+  int learningRate;
+  int noiseVariance;
+
+  cv::Mat img_foreground;
+  cv::Mat img_background;
+
+public:
+  LBFuzzyGaussian();
+  ~LBFuzzyGaussian();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+  //void finish(void);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/lb/LBMixtureOfGaussians.cpp b/package_bgs/lb/LBMixtureOfGaussians.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d235c506601f7b2a57379810c3fcd9c4ee75779
--- /dev/null
+++ b/package_bgs/lb/LBMixtureOfGaussians.cpp
@@ -0,0 +1,105 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "LBMixtureOfGaussians.h"
+
+LBMixtureOfGaussians::LBMixtureOfGaussians() : firstTime(true), showOutput(true), sensitivity(81), bgThreshold(83), learningRate(59), noiseVariance(206)
+{
+  std::cout << "LBMixtureOfGaussians()" << std::endl;
+}
+
+LBMixtureOfGaussians::~LBMixtureOfGaussians()
+{
+  delete m_pBGModel;
+  std::cout << "~LBMixtureOfGaussians()" << std::endl;
+}
+
+void LBMixtureOfGaussians::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+  
+  IplImage *frame = new IplImage(img_input);
+  
+  if(firstTime)
+  {
+    saveConfig();
+
+    int w = cvGetSize(frame).width;
+    int h = cvGetSize(frame).height;
+
+    m_pBGModel = new BGModelMog(w,h);
+    m_pBGModel->InitModel(frame);
+  }
+  
+  m_pBGModel->setBGModelParameter(0,sensitivity);
+  m_pBGModel->setBGModelParameter(1,bgThreshold);
+  m_pBGModel->setBGModelParameter(2,learningRate);
+  m_pBGModel->setBGModelParameter(3,noiseVariance);
+
+  m_pBGModel->UpdateModel(frame);
+
+  img_foreground = cv::Mat(m_pBGModel->GetFG());
+  img_background = cv::Mat(m_pBGModel->GetBG());
+    
+  if(showOutput)
+  {
+    cv::imshow("MOG Mask", img_foreground);
+    cv::imshow("MOG Model", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+  
+  delete frame;
+  
+  firstTime = false;
+}
+
+//void LBMixtureOfGaussians::finish(void)
+//{
+//  delete m_pBGModel;
+//}
+
+void LBMixtureOfGaussians::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBMixtureOfGaussians.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "sensitivity", sensitivity);
+  cvWriteInt(fs, "bgThreshold", bgThreshold);
+  cvWriteInt(fs, "learningRate", learningRate);
+  cvWriteInt(fs, "noiseVariance", noiseVariance);
+  
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void LBMixtureOfGaussians::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBMixtureOfGaussians.xml", 0, CV_STORAGE_READ);
+  
+  sensitivity = cvReadIntByName(fs, 0, "sensitivity", 81);
+  bgThreshold = cvReadIntByName(fs, 0, "bgThreshold", 83);
+  learningRate = cvReadIntByName(fs, 0, "learningRate", 59);
+  noiseVariance = cvReadIntByName(fs, 0, "noiseVariance", 206);
+  
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/lb/LBMixtureOfGaussians.h b/package_bgs/lb/LBMixtureOfGaussians.h
new file mode 100644
index 0000000000000000000000000000000000000000..71ab5f0c3f5309df637732dd563b26edc6c1f1af
--- /dev/null
+++ b/package_bgs/lb/LBMixtureOfGaussians.h
@@ -0,0 +1,55 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "BGModelMog.h"
+
+#include "../IBGS.h"
+
+using namespace lb_library;
+using namespace lb_library::MixtureOfGaussians;
+
+class LBMixtureOfGaussians : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+  
+  BGModel* m_pBGModel;
+  int sensitivity;
+  int bgThreshold;
+  int learningRate;
+  int noiseVariance;
+
+  cv::Mat img_foreground;
+  cv::Mat img_background;
+
+public:
+  LBMixtureOfGaussians();
+  ~LBMixtureOfGaussians();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+  //void finish(void);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/lb/LBSimpleGaussian.cpp b/package_bgs/lb/LBSimpleGaussian.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f0ce6fc69c6e572e1ebba8883af7706a117f91ad
--- /dev/null
+++ b/package_bgs/lb/LBSimpleGaussian.cpp
@@ -0,0 +1,100 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "LBSimpleGaussian.h"
+
+LBSimpleGaussian::LBSimpleGaussian() : firstTime(true), showOutput(true), sensitivity(66), noiseVariance(162), learningRate(18)
+{
+  std::cout << "LBSimpleGaussian()" << std::endl;
+}
+
+LBSimpleGaussian::~LBSimpleGaussian()
+{
+  delete m_pBGModel;
+  std::cout << "~LBSimpleGaussian()" << std::endl;
+}
+
+void LBSimpleGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+  
+  IplImage *frame = new IplImage(img_input);
+  
+  if(firstTime)
+  {
+    saveConfig();
+
+    int w = cvGetSize(frame).width;
+    int h = cvGetSize(frame).height;
+
+    m_pBGModel = new BGModelGauss(w,h);
+    m_pBGModel->InitModel(frame);
+  }
+  
+  m_pBGModel->setBGModelParameter(0,sensitivity);
+  m_pBGModel->setBGModelParameter(1,noiseVariance);
+  m_pBGModel->setBGModelParameter(2,learningRate);
+
+  m_pBGModel->UpdateModel(frame);
+
+  img_foreground = cv::Mat(m_pBGModel->GetFG());
+  img_background = cv::Mat(m_pBGModel->GetBG());
+    
+  if(showOutput)
+  {
+    cv::imshow("SG Mask", img_foreground);
+    cv::imshow("SG Model", img_background);
+  }
+
+  img_foreground.copyTo(img_output);
+  img_background.copyTo(img_bgmodel);
+  
+  delete frame;
+  
+  firstTime = false;
+}
+
+//void LBSimpleGaussian::finish(void)
+//{
+//  delete m_pBGModel;
+//}
+
+void LBSimpleGaussian::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBSimpleGaussian.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "sensitivity", sensitivity);
+  cvWriteInt(fs, "noiseVariance", noiseVariance);
+  cvWriteInt(fs, "learningRate", learningRate);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void LBSimpleGaussian::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/LBSimpleGaussian.xml", 0, CV_STORAGE_READ);
+  
+  sensitivity = cvReadIntByName(fs, 0, "sensitivity", 66);
+  noiseVariance = cvReadIntByName(fs, 0, "noiseVariance", 162);
+  learningRate = cvReadIntByName(fs, 0, "learningRate", 18);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/lb/LBSimpleGaussian.h b/package_bgs/lb/LBSimpleGaussian.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea8317c49496fac4e60fb42595d075fcf75218cd
--- /dev/null
+++ b/package_bgs/lb/LBSimpleGaussian.h
@@ -0,0 +1,54 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "BGModelGauss.h"
+
+#include "../IBGS.h"
+
+using namespace lb_library;
+using namespace lb_library::SimpleGaussian;
+
+class LBSimpleGaussian : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+  
+  BGModel* m_pBGModel;
+  int sensitivity;
+  int noiseVariance;
+  int learningRate;
+
+  cv::Mat img_foreground;
+  cv::Mat img_background;
+
+public:
+  LBSimpleGaussian();
+  ~LBSimpleGaussian();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+  //void finish(void);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/lb/Types.h b/package_bgs/lb/Types.h
new file mode 100644
index 0000000000000000000000000000000000000000..5b1fd5b358a7cf84c663a435a4c52e20530fefe5
--- /dev/null
+++ b/package_bgs/lb/Types.h
@@ -0,0 +1,99 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*  Scene 1.0.1 -- Background subtraction and object tracking for complex environments  
+Types.h
+
+Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#include <cv.h>
+
+namespace lb_library
+{
+  template<class T> class Image
+  {
+  private:
+    IplImage* imgp;
+
+  public:
+    Image(IplImage* img=0) {imgp=img;}
+    ~Image(){imgp=0;}
+  
+    void operator=(IplImage* img) {imgp=img;}
+  
+    inline T* operator[](const int rowIndx)
+    {
+      return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));
+    }
+  };
+
+  typedef struct{
+    unsigned char b,g,r;
+  } RgbPixel;
+
+  typedef struct{
+    unsigned char Blue,Green,Red;
+  } BYTERGB;
+
+  typedef struct{
+    unsigned int Blue,Green,Red;
+  } INTRGB;
+
+  typedef struct{
+    float b,g,r;
+  }RgbPixelFloat;
+
+  typedef struct{
+    double Blue,Green,Red;
+  } DBLRGB;
+
+  typedef Image<RgbPixel>       RgbImage;
+  typedef Image<RgbPixelFloat>  RgbImageFloat;
+  typedef Image<unsigned char>  BwImage;
+  typedef Image<float>          BwImageFloat;
+
+  /*
+  IplImage* img = cvCreateImage(cvSize(640,480), IPL_DEPTH_32F, 3);
+  RgbImageFloat imgA(img);
+  for(int i = 0; i < m_height; i++)
+    for(int j = 0; j < m_width; j++)
+      imgA[i][j].b = 111;
+      imgA[i][j].g = 111;
+      imgA[i][j].r = 111;
+  */
+}
+
+//---------------------------------------------
+
+#endif
diff --git a/package_bgs/my/MyBGS.cpp b/package_bgs/my/MyBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..07b51cde46b07c5da9e0ad19951d35aca191f771
--- /dev/null
+++ b/package_bgs/my/MyBGS.cpp
@@ -0,0 +1,26 @@
+#include "MyBGS.h"
+
+MyBGS::MyBGS(){}
+MyBGS::~MyBGS(){}
+
+void MyBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  if(img_previous.empty())
+    img_input.copyTo(img_previous);
+
+  cv::Mat img_foreground;
+  cv::absdiff(img_previous, img_input, img_foreground);
+
+  if(img_foreground.channels() == 3)
+    cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY);
+
+  cv::threshold(img_foreground, img_foreground, 15, 255, cv::THRESH_BINARY);
+
+  img_foreground.copyTo(img_output);
+  img_previous.copyTo(img_bgmodel);
+
+  img_input.copyTo(img_previous);
+}
diff --git a/package_bgs/my/MyBGS.h b/package_bgs/my/MyBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..daba73043a777e7ba97b60f539b4eaa4871b7d38
--- /dev/null
+++ b/package_bgs/my/MyBGS.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+
+class MyBGS : public IBGS
+{
+private:
+  cv::Mat img_previous;
+  
+public:
+  MyBGS();
+  ~MyBGS();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig(){}
+  void loadConfig(){}
+};
\ No newline at end of file
diff --git a/package_bgs/pt/PBAS.cpp b/package_bgs/pt/PBAS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f74b829f19c59ca2a30b58a5236b686786f01f6
--- /dev/null
+++ b/package_bgs/pt/PBAS.cpp
@@ -0,0 +1,586 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "PBAS.h"
+
+PBAS::PBAS(void) : N(20), R_lower(18), Raute_min(2), T_lower(2), T_upper(200), R_scale(5), R_incdec(0.05), T_dec(0.05), T_inc(1)
+{
+  std::cout << "PBAS()" << std::endl;
+
+  //feature vector
+  alpha = 7.0;
+  beta = 1.0;
+  formerMeanNorm = 0;
+  width = 0;
+
+  //result image
+  foregroundValue = 255;
+  backgroundValue = 0;
+
+  //length of random array
+  countOfRandomNumb = 1000;
+
+  //the T(x_i) value needs initiation 
+  T_init = R_lower;
+
+  //check if something is moving in the picture
+  isMove = false;
+
+  //for init, count number of runs
+  runs = 0;
+  newInitialization();
+}
+
+void PBAS::newInitialization()
+{
+  if(!randomN.empty())
+    randomN.clear();
+
+  if(!randomX.empty())
+    randomX.clear();
+
+  if(!randomY.empty())
+    randomY.clear();
+
+  if(!randomMinDist.empty())
+    randomMinDist.clear();
+
+  if(!randomT.empty())
+    randomT.clear();
+
+  if(!randomTN.empty())
+    randomTN.clear();
+
+  for(int l = 0; l < countOfRandomNumb; l++)
+  {
+    randomN.push_back((int)randomGenerator.uniform((int)0,(int)N));
+    randomX.push_back((int)randomGenerator.uniform(-1, +2));
+    randomY.push_back((int)randomGenerator.uniform(-1, +2));
+    randomMinDist.push_back((int)randomGenerator.uniform((int)0, (int)N));
+    randomT.push_back((int)randomGenerator.uniform((int)0, (int)T_upper));
+    randomTN.push_back((int)randomGenerator.uniform((int)0, (int)T_upper));
+  }
+}
+
+PBAS::~PBAS(void)
+{
+  std::cout << "~PBAS()" << std::endl;
+
+  randomN.clear();
+  randomX.clear();
+  randomY.clear();
+  randomMinDist.clear();
+  randomT.clear();
+  randomTN.clear();
+
+  for(int k = 0; k < backgroundModel.size(); ++k)
+  {
+    if(chans == 1)
+    {
+      backgroundModel.at(k).at(0).release();
+      backgroundModel.at(k).at(1).release();
+    }
+    else
+    {
+      backgroundModel.at(k).at(0).release();
+      backgroundModel.at(k).at(1).release();
+      backgroundModel.at(k).at(2).release();
+
+      backgroundModel.at(k).at(3).release();
+      backgroundModel.at(k).at(4).release();
+      backgroundModel.at(k).at(5).release();
+    }
+  }
+
+  backgroundModel.clear();
+  meanMinDist.release();
+
+  actualR.release();
+  actualT.release();
+
+  sobelX.release();
+  sobelY.release();
+}
+
+bool PBAS::process(cv::Mat* input, cv::Mat* output)
+{
+  if(width != input->cols)
+  {
+    width = input->cols;
+    chans = input->channels();
+    height = input->rows;
+
+    if(input->rows < 1  || input->cols < 1)
+    {
+      std::cout << "Error: Occurrence of to small (or empty?) image size in PBAS. STOPPING " << std::endl;
+      return false;
+    }
+  }
+
+  //iniate the background model
+  init(input);
+
+  resultMap = new cv::Mat(input->rows,input->cols,CV_8UC1);
+
+  //calculate features
+  calculateFeatures(&currentFeatures, input);
+
+  //set sumMagnitude to zero at beginning and then sum up in the loop
+  sumMagnitude = 0;
+  long glCounterFore = 0;
+  isMove = false;
+
+  //Here starts the whole processing of each pixel of the image
+  // for each pixel
+  for (int j=0; j< resultMap->rows; ++j) 
+  {
+    resultMap_Pt = resultMap->ptr<uchar>(j);
+    currentFeaturesM_Pt.clear();
+    currentFeaturesC_Pt.clear();
+    std::vector<float*> fT;
+    std::vector<uchar*> uT;
+    B_Mag_Pts.clear();
+    B_Col_Pts.clear();
+
+    for(int z = 0; z < chans; ++z)
+    {
+      currentFeaturesM_Pt.push_back(currentFeatures.at(z).ptr<float>(j));
+      currentFeaturesC_Pt.push_back(currentFeatures.at(z + chans).ptr<uchar>(j));
+
+      B_Mag_Pts.push_back(fT);
+
+      B_Col_Pts.push_back(uT);
+    }
+
+    meanMinDist_Pt = meanMinDist.ptr<float>(j);
+    actualR_Pt = actualR.ptr<float>(j);
+    actualT_Pt = actualT.ptr<float>(j);
+
+    for(int k = 0; k < runs; ++k)
+    {
+      for(int z = 0; z < chans; ++z)
+      {
+        B_Mag_Pts.at(z).push_back(backgroundModel.at(k).at(z).ptr<float>(j));
+        B_Col_Pts.at(z).push_back(backgroundModel.at(k).at(z+chans).ptr<uchar>(j));
+      }
+    }
+
+    for(int i = 0; i < resultMap->cols; ++i) 
+    {
+      //Compare each pixel to in the worst runtime-case each background model
+      int count = 0; 
+      int index = 0; 
+
+      double norm = 0.0;
+      double dist = 0.0;
+      double minDist = 1000.0;
+      int entry = randomGenerator.uniform(3, countOfRandomNumb-4);
+
+      do
+      {
+        if(chans == 3)
+        {
+          norm = sqrt(
+            (((double)B_Mag_Pts.at(0).at(index)[i] - ((double)*currentFeaturesM_Pt.at(0)))*((double)B_Mag_Pts.at(0).at(index)[i] - ((double)*currentFeaturesM_Pt.at(0))))+
+            (((double)B_Mag_Pts.at(1).at(index)[i] - ((double)*currentFeaturesM_Pt.at(1)))*((double)B_Mag_Pts.at(1).at(index)[i] - ((double)*currentFeaturesM_Pt.at(1))))+
+            (((double)B_Mag_Pts.at(2).at(index)[i] - ((double)*currentFeaturesM_Pt.at(2)))*((double)B_Mag_Pts.at(2).at(index)[i] - ((double)*currentFeaturesM_Pt.at(2))))
+            );				
+
+          dist = sqrt(
+            (((double)B_Col_Pts.at(0).at(index)[i] - ((double)*currentFeaturesC_Pt.at(0)))*((double)B_Col_Pts.at(0).at(index)[i] - ((double)*currentFeaturesC_Pt.at(0))))+
+            (((double)B_Col_Pts.at(1).at(index)[i] - ((double)*currentFeaturesC_Pt.at(1)))*((double)B_Col_Pts.at(1).at(index)[i] - ((double)*currentFeaturesC_Pt.at(1))))+
+            (((double)B_Col_Pts.at(2).at(index)[i] - ((double)*currentFeaturesC_Pt.at(2)))*((double)B_Col_Pts.at(2).at(index)[i] - ((double)*currentFeaturesC_Pt.at(2))))
+            );
+        }
+        else
+        {
+          norm = abs((((double)B_Mag_Pts.at(0).at(index)[i] - 
+          ((double)*currentFeaturesM_Pt.at(0)))*((double)B_Mag_Pts.at(0).at(index)[i] - ((double)*currentFeaturesM_Pt.at(0)))));				
+
+          dist = abs((((double)B_Col_Pts.at(0).at(index)[i] - 
+          ((double)*currentFeaturesC_Pt.at(0)))*((double)B_Col_Pts.at(0).at(index)[i] - ((double)*currentFeaturesC_Pt.at(0))))
+            );
+        }
+        dist = ((double)alpha*(norm/formerMeanMag) + beta*dist);
+
+        if((dist < *actualR_Pt)) 
+        {
+          ++count;
+          if(minDist > dist)
+            minDist = dist;
+        }
+        else
+        {
+          sumMagnitude += (double)(norm);
+          ++glCounterFore;
+        }
+        ++index;
+      }
+      while((count< Raute_min) && (index < runs));
+
+
+      //#############################################
+      //update backgroundmodel
+      // is BACKGROUND			
+      if(count >= Raute_min)
+      {
+        *resultMap_Pt = 0;
+        double ratio = std::ceil((double)T_upper/(double)(*actualT_Pt));
+        //in the first run every distance is zero, because there is no background model
+        //in the secont run, we have already one image as background model, hence a 
+        // reasonable minDist could be found -> because of the partly 1/run changing in the running average, we set in the first try meanMinDist to the actual minDist value
+        if(runs < N && runs > 2)
+        {
+          *meanMinDist_Pt = ((((float)(runs-1)) * (*meanMinDist_Pt)) + (float)minDist) / ((float)runs);
+        }
+        else if(runs < N && runs == 2)
+        {
+          *meanMinDist_Pt = (float)minDist;
+        }
+
+        //1. update model
+        if(runs == N)
+        {
+          //Update current pixel
+          //check if random numer is smaller than ratio
+          if(randomT.at(entry) < ratio)
+          {
+            // replace randomly chosen sample
+            int rand = randomN.at(entry+1); //randomGenerator.uniform((int)0,(int)N-1);
+            for(int z = 0; z < chans; ++z)
+            {
+              B_Mag_Pts.at(z).at(rand)[i] = (float)*currentFeaturesM_Pt.at(z);
+              B_Col_Pts.at(z).at(rand)[i] = (uchar)*currentFeaturesC_Pt.at(z);
+
+            }
+
+            *meanMinDist_Pt = ((((float)(N-1)) * (*meanMinDist_Pt)) + (float)minDist) / ((float)N);
+          }
+
+          //Update neighboring pixel model
+          if(randomTN.at(entry) < ratio)
+          {
+            //choose neighboring pixel randomly
+            int xNeigh = randomX.at(entry)+i;
+            int yNeigh = randomY.at(entry)+j;
+            checkValid(&xNeigh, &yNeigh);
+
+            // replace randomly chosen sample
+            int rand = randomN.at(entry-1); 
+            for(int z = 0; z < chans; ++z)
+            {
+              (backgroundModel.at(rand)).at(z).at<float>(yNeigh,xNeigh) = currentFeatures.at(z).at<float>(yNeigh,xNeigh);
+              (backgroundModel.at(rand)).at(z + chans).at<uchar>(yNeigh,xNeigh) = currentFeatures.at(z+chans).at<uchar>(yNeigh,xNeigh);
+            }
+          }
+        }
+      }
+      else
+      {
+        // store pixel as foreground
+        *resultMap_Pt = 255;
+
+        //there is some movement
+        isMove = true; 
+      }
+
+      //#######################//#######################//#######################//#######################
+      //control loops
+      //#######################//#######################//#######################//#######################
+      //update R		
+      decisionThresholdRegulator(actualR_Pt,meanMinDist_Pt);
+
+      //update T
+      learningRateRegulator(actualT_Pt, meanMinDist_Pt,resultMap_Pt);
+
+      //#######################//#######################//#######################//#######################
+      //#######################//#######################//#######################//#######################			
+
+      //jump to next pixel
+      ++resultMap_Pt;
+      for(int z = 0; z < chans; ++z)
+      {
+        ++currentFeaturesM_Pt.at(z);
+        ++currentFeaturesC_Pt.at(z);
+      }
+
+      ++meanMinDist_Pt;
+      ++actualR_Pt;
+      ++actualT_Pt;			
+    }
+  }
+
+  resultMap->copyTo(*output);
+
+  //if there is no foreground -> no magnitudes fount
+  //-> initiate some low value to prevent diving through zero
+  double meanMag = sumMagnitude/(double)(glCounterFore + 1); //height*width);
+
+  if(meanMag > 20)
+    formerMeanMag = meanMag;
+  else
+    formerMeanMag = 20;
+
+  delete resultMap;
+
+  for(int z = 0; z < chans; ++z)
+  {
+    currentFeatures.at(z+chans).release();
+    currentFeatures.at(z).release();
+  }
+
+  return true;
+}
+
+void PBAS::decisionThresholdRegulator(float* pt, float* meanDist)
+{
+  //update R
+  double tempR = *pt;
+  double newThresh = (*meanDist)*R_scale;
+
+  if( tempR < newThresh)
+  {
+    tempR += tempR * R_incdec;
+  }
+  else
+  {
+    tempR -= tempR * R_incdec;
+  }
+
+  if(tempR >= R_lower)
+    *pt = (float)tempR;	
+  else
+    *pt = (float)R_lower;
+}
+
+void PBAS::learningRateRegulator(float* pt, float* meanDist,uchar* isFore)
+{
+  //time update
+  double tempT = *pt;
+
+  if((int)*isFore < 128)
+  {
+    tempT -= T_inc/(*meanDist+1.0);
+  }
+  else
+  {
+    tempT += T_dec/(*meanDist+1.0);
+  }
+
+  if(tempT > T_lower && tempT < T_upper)
+    *pt = (float)tempT;
+}
+
+void PBAS::checkValid(int *x, int *y)
+{
+  if(*x < 0)
+  {
+    *x = 0;
+  }
+  else if(*x >= width)
+  {
+    *x = width -1;
+  }
+
+  if(*y < 0)
+  {
+    *y = 0;
+  }
+  else if(*y >= height)
+  {
+    *y = height - 1;
+  }
+}
+
+void PBAS::init(cv::Mat* input)
+{
+  if(runs < N)
+  {
+    std::vector<cv::Mat> init;
+    calculateFeatures(&init, input);
+    backgroundModel.push_back(init);
+
+    if(chans == 1)
+    {
+      init.at(0).release();
+      init.at(1).release();
+    }
+    else
+    {
+      init.at(0).release();
+      init.at(1).release();
+      init.at(2).release();
+      init.at(3).release();
+      init.at(4).release();
+      init.at(5).release();
+    }
+
+    init.clear();
+
+    if(runs == 0)
+    {	
+      meanMinDist.create(input->size(), CV_32FC1);
+      meanMinDist.zeros(input->rows, input->cols, CV_32FC1);
+
+      actualR.create(input->rows, input->cols, CV_32FC1);
+      actualT.create(input->rows, input->cols, CV_32FC1);
+
+      float* ptRs, *ptTs; //, *ptM;
+      for(int rows = 0; rows < actualR.rows; ++rows)
+      {
+        ptRs = actualR.ptr<float>(rows);
+        ptTs = actualT.ptr<float>(rows);
+
+        for(int cols = 0; cols < actualR.cols; ++cols)
+        {
+          ptRs[cols] = (float)R_lower;
+          ptTs[cols] = (float)T_init;
+        }
+      }
+    }
+
+    ++runs;
+  }
+}
+
+void PBAS::calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage)
+{
+  if(!feature->empty())
+    feature->clear();
+
+  cv::Mat mag[3], dir;
+
+  if(inputImage->channels() == 3)
+  {
+    std::vector<cv::Mat> rgbChannels(3);
+    cv::split(*inputImage, rgbChannels);
+
+    for(int l = 0; l < 3; ++l)
+    {
+      cv::Sobel(rgbChannels.at(l),sobelX,CV_32F,1,0, 3, 1, 0.0);
+      cv::Sobel(rgbChannels.at(l),sobelY,CV_32F,0,1, 3, 1, 0.0);
+
+      // Compute the L2 norm and direction of the gradient
+      cv::cartToPolar(sobelX,sobelY,mag[l],dir, true);
+      feature->push_back(mag[l]);
+      sobelX.release();
+      sobelY.release();
+    }
+
+    feature->push_back(rgbChannels.at(0));
+    feature->push_back(rgbChannels.at(1));
+    feature->push_back(rgbChannels.at(2));
+    rgbChannels.at(0).release();
+    rgbChannels.at(1).release();
+    rgbChannels.at(2).release();
+  }
+  else
+  {
+    cv::Sobel(*inputImage,sobelX,CV_32F,1,0, 3, 1, 0.0);
+    cv::Sobel(*inputImage,sobelY,CV_32F,0,1, 3, 1, 0.0);
+
+    // Compute the L2 norm and direction of the gradient
+    cv::cartToPolar(sobelX,sobelY,mag[0],dir, true);
+    feature->push_back(mag[0]);
+
+    cv::Mat temp;
+    inputImage->copyTo(temp);
+    feature->push_back(temp);
+    temp.release();
+  }
+
+  mag[0].release();
+  mag[1].release();
+  mag[2].release();
+  dir.release();
+}
+
+void PBAS::setN(int temp)
+{
+  N = temp;
+  newInitialization();
+}
+
+void PBAS::setRaute_min(int temp)
+{
+  Raute_min = temp;
+}
+
+void PBAS::setR_lower(double temp)
+{
+  R_lower = temp;
+}
+
+void PBAS::setR_incdec(double temp)
+{
+  R_incdec = temp;
+}
+
+void PBAS::setR_scale(double temp)
+{
+  R_scale = temp;
+}
+
+void PBAS::setT_init(double temp)
+{
+  T_init = temp;
+}
+
+void PBAS::setT_lower(double temp)
+{
+  T_lower = temp;
+}
+
+void PBAS::setT_upper(double temp)
+{
+  T_upper = temp;
+  newInitialization();
+}
+
+void PBAS::setT_dec(double temp)
+{
+  T_dec = temp;
+}
+
+void PBAS::setT_inc(double temp)
+{
+  T_inc = temp;
+}
+
+void PBAS::setAlpha(double temp)
+{
+  alpha = temp;
+}
+
+void PBAS::setBeta(double temp)
+{
+  beta = temp;
+}
+
+bool PBAS::isMovement()
+{
+  return isMove;
+}
+
+//cv::Mat* PBAS::getR1_xi()
+//{
+//	return &actualR;
+//}
+//
+//cv::Mat* PBAS::getT_xi()
+//{
+//	return &actualT;
+//}
diff --git a/package_bgs/pt/PBAS.h b/package_bgs/pt/PBAS.h
new file mode 100644
index 0000000000000000000000000000000000000000..917c525bfb2af10f849dc2d746b3a6c4db2c127c
--- /dev/null
+++ b/package_bgs/pt/PBAS.h
@@ -0,0 +1,207 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+//Implementation of the PBAS from:
+//
+//M. Hofmann, P. Tiefenbacher, G. Rigoll 
+//"Background Segmentation with Feedback: The Pixel-Based Adaptive Segmenter", 
+//in proc of IEEE Workshop on Change Detection, 2012
+//
+//Note: some changes, to improve the speed and memory requirements, were achieved in comparison to the 
+//described PBAS algorithm in the paper above.
+//
+//Example usage:
+// //Somewhere during initalization:
+// #include "PBAS.h"
+// #include <opencv2/opencv.hpp>
+// PBAS pbas;
+//
+// //you might want to change some parameters of the PBAS here...
+// ....
+//
+// //repeat for each frame
+// //make gaussian blur for reducing image noise
+//cv::Mat bluredImage;
+//cv::Mat pbastResult;
+//cv::GaussianBlur(singleFrame, bluredImage, cv::Size(5,5), 1.5);
+// 
+// //process image and receive segmentation in pbasResult
+//pbas.process(&bluredImage, &pbasResult);
+//
+// //make medianBlur on the result to reduce "salt and pepper noise"
+// //of the per pixel wise segmentation
+//cv::medianBlur(pbasResult, pbasResult, 5);
+//
+//
+//
+//Author: P.Tiefenbacher, https://sites.google.com/site/pbassegmenter/
+//Technische Universit�t M�nchen, Germany
+//Date: 22-May-2012, Version:0.1
+///////////
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#pragma once
+class PBAS
+{
+public:
+	PBAS(void);
+	~PBAS(void);
+	bool process(cv::Mat* input, cv::Mat* output);
+
+	void setN(int);
+	void setRaute_min(int);
+	void setR_lower(double);
+	void setR_incdec(double);
+	void setR_scale(double);
+	void setT_init(double);
+	void setT_lower(double);
+	void setT_upper(double);
+	void setT_dec(double);
+	void setT_inc(double);
+	void setAlpha(double);
+	void setBeta(double);
+
+	bool isMovement();
+	
+
+private:
+	void calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage);
+	void checkValid(int *x, int *y);
+	void decisionThresholdRegulator(float* pt, float* meanDistArr);
+	void learningRateRegulator(float* pt, float* meanDist,uchar* isFore);
+	void init(cv::Mat*);
+	void newInitialization();
+
+	cv::Mat meanMinDist;
+	float* meanMinDist_Pt;
+
+
+
+	int width, height;
+	int chans;
+
+	//balance of feature pixel value to conture value
+	double alpha, beta;
+	//##################################################################################
+	
+	double formerMeanNorm;
+
+	//define value of foreground/background pixels
+	int foregroundValue, backgroundValue;
+
+	//##################################################################################
+	//random number parameters
+	
+	//random number generator
+	cv::RNG randomGenerator;
+	
+	//length of random array initialization
+	long countOfRandomNumb;
+
+	//pre - initialize the randomNumbers for better performance
+	std::vector<int> randomN, randomMinDist, randomX, randomY, randomT, randomTN;
+	
+	//###################################################################################
+
+	//check if something is moving
+	bool isMove;
+
+	//for init, count number of runs
+	int runs;
+
+
+	cv::Mat* resultMap;
+	std::vector<cv::Mat> currentFeatures;
+
+	std::vector<float*> currentFeaturesM_Pt; 
+	std::vector<uchar*> currentFeaturesC_Pt; 
+	uchar* resultMap_Pt;
+	
+	std::vector<std::vector<float*>>B_Mag_Pts;
+	std::vector<std::vector<uchar*>>B_Col_Pts;
+	
+	double sumMagnitude;
+	double formerMeanMag;
+	float formerDistanceBack;
+
+	//####################################################################################
+	//N - Number: Defining the size of the background-history-model
+	// number of samples per pixel
+	//size of background history B(x_i)
+	int N;
+	// background model
+	std::vector<std::vector<cv::Mat>> backgroundModel;
+	//####################################################################################
+	//####################################################################################
+	//R-Threshhold - Variables
+	//minimal Threshold for foreground and initial value of R(x_i)
+	// radius of the sphere -> lower border boundary
+	double R_lower;
+
+	//factor which defines new threshold of R(x_i) together with meanMinDist(x_i)
+	// scale for the sphere threshhold to define pixel-based Thresholds
+	double R_scale;
+	
+	//decreasing / increasing factor of R(x_i)
+	// increasing/decreasing factor for the r-Threshold based on the result of rTreshScale * meanMinDistBackground
+	double R_incdec;
+	
+	cv::Mat actualR; 
+	float* actualR_Pt; //new pixel-based r-threshhold -> pointer to arrays
+	//#####################################################################################
+	//####################################################################################
+	//counter for minimal distance to background
+	// Defining the number of background-model-images, which have a lowerDIstance to the current Image than defined by the R-Thresholds, that are necessary
+	// to decide that this pixel is background
+	int Raute_min;
+	//#####################################################################################
+	//####################################################################################
+	//initial value of inverse update factor T(x_i)
+	// Initialize the background-model update rate 
+	double T_init;
+
+	//increasing Factor of the update rate 1/T(x_i)
+	// scale that defines the increasing of the update rate of the background model, if the current pixel is background 
+	//--> more frequently updates if pixel is background because, there shouln't be any change
+	double T_inc;
+	
+	//upper boundary of T(x_i)
+	// defining an upper value, that nrSubsampling can achieve, thus it doesn't reach to an infinite value, where actually no update is possible 
+	// at all
+	double T_upper;	
+	
+	//lower boundary of T(x_i)
+	// defining a minimum value for nrSubsampling --> base value 2.0
+	double T_lower;
+	
+	//decreasing factor of the update rate 1/T(x_i)
+	// opposite scale to increasingRateScale, for decreasing the update rate of the background model, if the current pixel is foreground
+	//--> Thesis: Our Foreground is a real moving object -> thus the background-model is good, so don't update it
+	double T_dec;
+
+	//holds update rate of current pixel
+	cv::Mat actualT; 
+	float* actualT_Pt; 
+	
+	//#####################################################################################
+
+
+	cv::Mat sobelX, sobelY;
+};
+
diff --git a/package_bgs/pt/PixelBasedAdaptiveSegmenter.cpp b/package_bgs/pt/PixelBasedAdaptiveSegmenter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..10c8e8e1f87511906ef8b8bac25ecd82f01d186b
--- /dev/null
+++ b/package_bgs/pt/PixelBasedAdaptiveSegmenter.cpp
@@ -0,0 +1,124 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "PixelBasedAdaptiveSegmenter.h"
+
+PixelBasedAdaptiveSegmenter::PixelBasedAdaptiveSegmenter() : firstTime(true), showOutput(true), enableInputBlur(true), enableOutputBlur(true),
+alpha(7.0), beta(1.0), N(20), Raute_min(2), R_incdec(0.05), R_lower(18),
+R_scale(5), T_dec(0.05), T_inc(1), T_init(18), T_lower(2), T_upper(200)
+{
+  std::cout << "PixelBasedAdaptiveSegmenter()" << std::endl;
+}
+
+PixelBasedAdaptiveSegmenter::~PixelBasedAdaptiveSegmenter()
+{
+  std::cout << "~PixelBasedAdaptiveSegmenter()" << std::endl;
+}
+
+void PixelBasedAdaptiveSegmenter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    pbas.setAlpha(alpha);
+    pbas.setBeta(beta);
+    pbas.setN(N);
+    pbas.setRaute_min(Raute_min);
+    pbas.setR_incdec(R_incdec);
+    pbas.setR_lower(R_lower);
+    pbas.setR_scale(R_scale);
+    pbas.setT_dec(T_dec);
+    pbas.setT_inc(T_inc);
+    pbas.setT_init(T_init);
+    pbas.setT_lower(T_lower);
+    pbas.setT_upper(T_upper);
+
+    saveConfig();
+  }
+
+  cv::Mat img_input_new;
+  if(enableInputBlur)
+    cv::GaussianBlur(img_input, img_input_new, cv::Size(5,5), 1.5);
+  else
+    img_input.copyTo(img_input_new);
+
+  cv::Mat img_foreground;
+  pbas.process(&img_input_new, &img_foreground);
+
+  if(enableOutputBlur)
+    cv::medianBlur(img_foreground, img_foreground, 5);
+
+  if(showOutput)
+    cv::imshow("PBAS", img_foreground);
+
+  img_foreground.copyTo(img_output);
+
+  firstTime = false;
+}
+
+void PixelBasedAdaptiveSegmenter::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/PixelBasedAdaptiveSegmenter.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "enableInputBlur", enableInputBlur);
+  cvWriteInt(fs, "enableOutputBlur", enableOutputBlur);
+  
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteReal(fs, "beta", beta);
+  cvWriteInt(fs, "N", N);
+  cvWriteInt(fs, "Raute_min", Raute_min);
+  cvWriteReal(fs, "R_incdec", R_incdec);
+  cvWriteInt(fs, "R_lower", R_lower);
+  cvWriteInt(fs, "R_scale", R_scale);
+  cvWriteReal(fs, "T_dec", T_dec);
+  cvWriteInt(fs, "T_inc", T_inc);
+  cvWriteInt(fs, "T_init", T_init);
+  cvWriteInt(fs, "T_lower", T_lower);
+  cvWriteInt(fs, "T_upper", T_upper);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void PixelBasedAdaptiveSegmenter::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/PixelBasedAdaptiveSegmenter.xml", 0, CV_STORAGE_READ);
+  
+  enableInputBlur = cvReadIntByName(fs, 0, "enableInputBlur", true);
+  enableOutputBlur = cvReadIntByName(fs, 0, "enableOutputBlur", true);
+  
+  alpha = cvReadRealByName(fs, 0, "alpha", 7.0);
+  beta = cvReadRealByName(fs, 0, "beta", 1.0);
+  N = cvReadIntByName(fs, 0, "N", 20);
+  Raute_min = cvReadIntByName(fs, 0, "Raute_min", 2);
+  R_incdec = cvReadRealByName(fs, 0, "R_incdec", 0.05);
+  R_lower = cvReadIntByName(fs, 0, "R_lower", 18);
+  R_scale = cvReadIntByName(fs, 0, "R_scale", 5);
+  T_dec = cvReadRealByName(fs, 0, "T_dec", 0.05);
+  T_inc = cvReadIntByName(fs, 0, "T_inc", 1);
+  T_init = cvReadIntByName(fs, 0, "T_init", 18);
+  T_lower = cvReadIntByName(fs, 0, "T_lower", 2);
+  T_upper = cvReadIntByName(fs, 0, "T_upper", 200);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/pt/PixelBasedAdaptiveSegmenter.h b/package_bgs/pt/PixelBasedAdaptiveSegmenter.h
new file mode 100644
index 0000000000000000000000000000000000000000..35409b5b28e6db9b33bab34e92131a84c1c8402f
--- /dev/null
+++ b/package_bgs/pt/PixelBasedAdaptiveSegmenter.h
@@ -0,0 +1,58 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "PBAS.h"
+#include "../IBGS.h"
+
+class PixelBasedAdaptiveSegmenter : public IBGS
+{
+private:
+  PBAS pbas;
+
+  bool firstTime;
+  bool showOutput;
+  bool enableInputBlur;
+  bool enableOutputBlur;
+
+  float alpha;
+  float beta;
+  int N;
+  int Raute_min;
+  float R_incdec;
+  int R_lower;
+  int R_scale;
+  float T_dec;
+  int T_inc;
+  int T_init;
+  int T_lower;
+  int T_upper;
+
+public:
+  PixelBasedAdaptiveSegmenter();
+  ~PixelBasedAdaptiveSegmenter();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
\ No newline at end of file
diff --git a/package_bgs/sjn/SJN_MultiCueBGS.cpp b/package_bgs/sjn/SJN_MultiCueBGS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..55a79373839976ace5803f06886fe31fc7a4d60a
--- /dev/null
+++ b/package_bgs/sjn/SJN_MultiCueBGS.cpp
@@ -0,0 +1,2062 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+//------------------------------------------------------------------------------------------------------------------------------------//
+//									A BGS Method Using Multiple Color, Texture, Appearance Cues in the Scene						  //
+//																																	  //
+//  - Paper: A New Framework for Background Subtraction Using Multiple Cues (ACCV2012)												  //
+//  - Code by: SeungJon Noh																											  //
+//------------------------------------------------------------------------------------------------------------------------------------//
+//#include "StdAfx.h"
+#include "SJN_MultiCueBGS.h"
+SJN_MultiCueBGS::SJN_MultiCueBGS() : firstTime(true), showOutput(true)
+{
+	//----------------------------------
+	//	User adjustable parameters
+	//----------------------------------			
+	g_iTrainingPeriod = 20;											//the training period								(The parameter t in the paper)
+	g_iT_ModelThreshold = 1;										//the threshold for texture-model based BGS.		(The parameter tau_T in the paper)
+	g_iC_ModelThreshold = 10;										//the threshold for appearance based verification.  (The parameter tau_A in the paper)
+	
+	g_fLearningRate = 0.05;											//the learning rate for background models.			(The parameter alpha in the paper)
+	
+	g_nTextureTrainVolRange = 15;									//the codebook size factor for texture models.		(The parameter k in the paper)
+	g_nColorTrainVolRange = 20;										//the codebook size factor for color models.		(The parameter eta_1 in the paper)
+	
+	g_bAbsorptionEnable = TRUE;										//If TRUE, cache-book is also modeled for ghost region removal.
+	g_iAbsortionPeriod = 200;										//the period to absorb static ghost regions 
+	
+	g_iRWidth = 160, g_iRHeight = 120;								//Frames are precessed after reduced in this size .
+
+	//------------------------------------
+	//	For codebook maintenance
+	//------------------------------------
+	g_iBackClearPeriod = 300;										//the period to clear background models	
+	g_iCacheClearPeriod = 30;										//the period to clear cache-book models	
+
+	//------------------------------------
+	//	Initialization of other parameters
+	//------------------------------------
+	g_nNeighborNum = 6, g_nRadius = 2;													
+	g_fConfidenceThre = g_iT_ModelThreshold/(float)g_nNeighborNum;	//the final decision threshold
+
+	g_iFrameCount = 0;
+	g_bForegroundMapEnable = FALSE;									//TRUE only when BGS is successful
+	g_bModelMemAllocated = FALSE;									//To handle memory..
+	g_bNonModelMemAllocated = FALSE;								//To handle memory..
+}
+
+SJN_MultiCueBGS::~SJN_MultiCueBGS(void){
+	Destroy();
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//											the main function to background modeling and subtraction									   //																   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel){
+
+  if (img_input.empty())
+    return;
+
+  loadConfig();
+
+  if (firstTime)
+    saveConfig();
+
+	//--STep1: Background Modeling--//
+	IplImage* frame = &IplImage(img_input);
+	IplImage* result_image = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
+	cvSetZero(result_image);
+
+	if(g_iFrameCount <= g_iTrainingPeriod){
+		BackgroundModeling_Par(frame);
+		g_iFrameCount++;	
+	}
+
+	//--Step2: Background Subtraction--//
+	else{
+		g_bForegroundMapEnable = FALSE;
+
+		ForegroundExtraction(frame);
+		UpdateModel_Par();
+
+		//Get BGS Results
+		GetForegroundMap(result_image, NULL);
+	}
+
+	cv::Mat temp(result_image,TRUE);
+	temp.copyTo(img_output);
+
+	cvReleaseImage(&result_image);
+  
+  if (showOutput)
+  {
+    cv::imshow("MultiCueBGS FG", img_output);
+  }
+
+  firstTime = false;
+}
+
+void SJN_MultiCueBGS::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MultiCueBGS.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void SJN_MultiCueBGS::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/MultiCueBGS.xml", 0, CV_STORAGE_READ);
+
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//													the system initialization function													   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::Initialize(IplImage* frame)
+{
+	int i,j;
+
+	g_iHeight = frame->height;
+	g_iWidth = frame->width;
+
+	Destroy();	
+
+	//--------------------------------------------------------
+	// memory initialization
+	//--------------------------------------------------------
+	g_ResizedFrame = cvCreateImage(cvSize(g_iRWidth, g_iRHeight), IPL_DEPTH_8U, 3);
+
+	g_aGaussFilteredFrame = (uchar***)malloc(sizeof(uchar**)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++){
+		g_aGaussFilteredFrame[i] = (uchar**)malloc(sizeof(uchar*)*g_iRWidth);
+		for(j=0;j<g_iRWidth;j++) g_aGaussFilteredFrame[i][j] = (uchar*)malloc(sizeof(uchar)*3);
+	}
+	
+	g_aXYZFrame = (uchar***)malloc(sizeof(uchar**)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++){
+		g_aXYZFrame[i] = (uchar**)malloc(sizeof(uchar*)*g_iRWidth);
+		for(j=0;j<g_iRWidth;j++) g_aXYZFrame[i][j] = (uchar*)malloc(sizeof(uchar)*3);
+	}
+
+	g_aLandmarkArray = (uchar**)malloc(sizeof(uchar*)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++) g_aLandmarkArray[i] = (uchar*)malloc(sizeof(uchar)*g_iRWidth);
+
+	g_aResizedForeMap = (uchar**)malloc(sizeof(uchar*)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++) g_aResizedForeMap[i] = (uchar*)malloc(sizeof(uchar)*g_iRWidth);
+
+	g_aForegroundMap = (uchar**)malloc(sizeof(uchar*)*g_iHeight);
+	for(i=0;i<g_iHeight;i++) g_aForegroundMap[i] = (uchar*)malloc(sizeof(uchar)*g_iWidth);
+
+	g_aUpdateMap = (BOOL**)malloc(sizeof(BOOL*)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++) g_aUpdateMap[i] = (BOOL*)malloc(sizeof(BOOL)*g_iRWidth);
+
+	//Bound Box Related..
+	int iElementNum = 300;
+	g_BoundBoxInfo = (BoundingBoxInfo*)malloc(sizeof(BoundingBoxInfo));
+	g_BoundBoxInfo->m_iArraySize = iElementNum;					
+	g_BoundBoxInfo->m_iBoundBoxNum = iElementNum;				
+
+	g_BoundBoxInfo->m_aLeft = (short*)malloc( sizeof(short) * iElementNum ); g_BoundBoxInfo->m_aRight = (short*)malloc( sizeof(short) * iElementNum );
+	g_BoundBoxInfo->m_aBottom = (short*)malloc( sizeof(short) * iElementNum ); g_BoundBoxInfo->m_aUpper = (short*)malloc( sizeof(short) * iElementNum );
+
+	g_BoundBoxInfo->m_aRLeft = (short*)malloc( sizeof(short) * iElementNum ); g_BoundBoxInfo->m_aRRight = (short*)malloc( sizeof(short) * iElementNum );
+	g_BoundBoxInfo->m_aRBottom = (short*)malloc( sizeof(short) * iElementNum ); g_BoundBoxInfo->m_aRUpper = (short*)malloc( sizeof(short) * iElementNum );
+
+	g_BoundBoxInfo->m_ValidBox = (BOOL*)malloc( sizeof(BOOL) * iElementNum );
+
+	//--------------------------------------------------------
+	// texture model related
+	//--------------------------------------------------------
+	T_AllocateTextureModelRelatedMemory();
+
+	//--------------------------------------------------------
+	// color moddel related
+	//--------------------------------------------------------
+	C_AllocateColorModelRelatedMemory();
+
+	g_bModelMemAllocated = TRUE;	
+	g_bNonModelMemAllocated = TRUE;
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//												the function to release allocated memories											       //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::Destroy()
+{
+	if(g_bModelMemAllocated==FALSE && g_bNonModelMemAllocated==FALSE) return;
+	
+	int i,j;
+	short nNeighborNum = g_nNeighborNum; 
+	
+	if(g_bModelMemAllocated==TRUE){	
+		T_ReleaseTextureModelRelatedMemory();
+		C_ReleaseColorModelRelatedMemory();
+		
+		g_bModelMemAllocated = FALSE;
+	}
+	
+	if(g_bNonModelMemAllocated==TRUE){
+		
+		cvReleaseImage(&g_ResizedFrame);
+
+		for(i=0;i<g_iRHeight;i++){
+			for(j=0;j<g_iRWidth;j++) free(g_aGaussFilteredFrame[i][j]);
+			free(g_aGaussFilteredFrame[i]);
+		}
+		free(g_aGaussFilteredFrame);
+	
+		for(i=0;i<g_iRHeight;i++){
+			for(j=0;j<g_iRWidth;j++) free(g_aXYZFrame[i][j]);
+			free(g_aXYZFrame[i]);
+		}
+		free(g_aXYZFrame);
+	
+		for(i=0;i<g_iRHeight;i++) free(g_aLandmarkArray[i]);
+		free(g_aLandmarkArray);
+
+		for(i=0;i<g_iRHeight;i++) free(g_aResizedForeMap[i]);
+		free(g_aResizedForeMap);
+	
+		for(i=0;i<g_iHeight;i++) free(g_aForegroundMap[i]);
+		free(g_aForegroundMap);
+
+		for(i=0;i<g_iRHeight;i++) free(g_aUpdateMap[i]);
+		free(g_aUpdateMap);
+
+		free(g_BoundBoxInfo->m_aLeft); free(g_BoundBoxInfo->m_aRight); free(g_BoundBoxInfo->m_aBottom); free(g_BoundBoxInfo->m_aUpper);
+		free(g_BoundBoxInfo->m_aRLeft); free(g_BoundBoxInfo->m_aRRight); free(g_BoundBoxInfo->m_aRBottom); free(g_BoundBoxInfo->m_aRUpper);
+		free(g_BoundBoxInfo->m_ValidBox);
+		free(g_BoundBoxInfo);
+
+		g_bNonModelMemAllocated = FALSE;
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the preprocessing function		    											   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::PreProcessing(IplImage* frame){
+
+	//image resize
+	ReduceImageSize(frame, g_ResizedFrame);
+	
+	//Gaussian filtering
+	GaussianFiltering(g_ResizedFrame, g_aGaussFilteredFrame);
+
+	//color space conversion
+	BGR2HSVxyz_Par(g_aGaussFilteredFrame,g_aXYZFrame);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the background modeling function												   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::BackgroundModeling_Par(IplImage* frame){
+	
+	//initialization
+	if(g_iFrameCount == 0) Initialize(frame);
+
+	//Step1: pre-processing
+	PreProcessing(frame);
+
+	int iH_Start = g_nRadius, iH_end = g_iRHeight-g_nRadius;
+	int iW_Start = g_nRadius, iW_end = g_iRWidth-g_nRadius;
+
+	float fLearningRate = g_fLearningRate * 4;
+
+	//Step2: background modeling
+	for(int i=iH_Start; i<iH_end; i++){
+		for(int j=iW_Start;j<iW_end;j++){
+			point center;
+			center.m_nX = j;
+			center.m_nY = i;
+			
+			T_ModelConstruction(g_nTextureTrainVolRange,fLearningRate,g_aXYZFrame,center,g_aNeighborDirection[i][j],g_TextureModel[i][j]);
+			C_CodebookConstruction(g_aXYZFrame[i][j], j, i, g_nColorTrainVolRange, fLearningRate, g_ColorModel[i][j]);
+		}
+	}
+
+	//Step3: Clear non-essential codewords
+	if(g_iFrameCount==g_iTrainingPeriod){
+		for(int i=0; i<g_iRHeight; i++){
+			for(int j=0;j<g_iRWidth;j++){
+				T_ClearNonEssentialEntries(g_iTrainingPeriod,g_TextureModel[i][j]);
+
+				C_ClearNonEssentialEntries(g_iTrainingPeriod,g_ColorModel[i][j]);
+			}
+		}
+		g_iFrameCount++;
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the background subtraction function							                       //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::ForegroundExtraction(IplImage* frame){
+
+	//Step1:pre-processing
+	PreProcessing(frame);
+
+	//Step3: texture-model based process
+	T_GetConfidenceMap_Par(g_aXYZFrame,g_aTextureConfMap,g_aNeighborDirection,g_TextureModel);
+	
+	//Step2: color-model based verification
+	CreateLandmarkArray_Par(g_fConfidenceThre,g_nColorTrainVolRange,g_aTextureConfMap,g_nNeighborNum,g_aXYZFrame, g_aNeighborDirection,
+							g_TextureModel,g_ColorModel,g_aLandmarkArray);
+
+	//Step3: verification procedures
+	PostProcessing(frame);
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the post-processing function													   //												
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::PostProcessing(IplImage* frame){
+
+	//Step1: morphological operation	
+	MorphologicalOpearions(g_aLandmarkArray,g_aResizedForeMap,0.5,5,g_iRWidth,g_iRHeight);
+	g_bForegroundMapEnable = TRUE;
+
+	//Step2: labeling
+	int** aLabelTable = (int**)malloc(sizeof(int*)*g_iRHeight);
+	for(int i=0;i<g_iRHeight;i++)  aLabelTable[i] = (int*)malloc(sizeof(int)*g_iRWidth);
+
+	int iLabelCount;
+	Labeling(g_aResizedForeMap,&iLabelCount,aLabelTable);
+
+	//Step3: getting bounding boxes for each candidate fore-blob
+	SetBoundingBox(iLabelCount, aLabelTable);
+	
+	//Step4: size  and appearance based verification
+	BoundBoxVerification(frame,g_aResizedForeMap,g_BoundBoxInfo);
+
+	//Step5: ��ȿ�� Foreground Region�鸸�� ��� �������� ����
+	RemovingInvalidForeRegions(g_aResizedForeMap,g_BoundBoxInfo);	
+
+	for(int i=0;i<g_iRHeight;i++) free(aLabelTable[i]);
+	free(aLabelTable);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the background-model update function			                                   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::UpdateModel_Par(){
+	short nNeighborNum = g_nNeighborNum;
+
+	//Step1: update map construction
+	for(int i=0;i<g_iRHeight;i++){
+		for(int j=0;j<g_iRWidth;j++){
+			g_aUpdateMap[i][j] = TRUE;
+		}
+	}
+
+	for(int k=0;k<g_BoundBoxInfo->m_iBoundBoxNum;k++){
+		if(g_BoundBoxInfo->m_ValidBox[k]==TRUE){
+			for(int i=g_BoundBoxInfo->m_aRUpper[k]; i<=g_BoundBoxInfo->m_aRBottom[k]; i++){
+				for(int j=g_BoundBoxInfo->m_aRLeft[k]; j<=g_BoundBoxInfo->m_aRRight[k]; j++){
+					g_aUpdateMap[i][j] = FALSE;
+				}
+			}
+		}
+	}
+
+	//Step2: update
+	int iH_Start = g_nRadius, iH_End = g_iRHeight-g_nRadius;
+	int iW_Start = g_nRadius, iW_End = g_iRWidth-g_nRadius;
+
+	float fLearningRate = (float)g_fLearningRate;
+
+	for(int i=iH_Start; i<iH_End; i++){
+		for(int j=iW_Start;j<iW_End;j++){
+
+			point center;
+
+			center.m_nX = j;
+			center.m_nY = i;
+
+			if(g_aUpdateMap[i][j]==TRUE){
+				//model update		
+				T_ModelConstruction(g_nTextureTrainVolRange,fLearningRate,g_aXYZFrame,center,g_aNeighborDirection[i][j],g_TextureModel[i][j]);
+				C_CodebookConstruction(g_aXYZFrame[i][j],j,i,g_nColorTrainVolRange,fLearningRate,g_ColorModel[i][j]);
+
+				//clearing non-essential codewords
+				T_ClearNonEssentialEntries(g_iBackClearPeriod,g_TextureModel[i][j]);
+				C_ClearNonEssentialEntries(g_iBackClearPeriod,g_ColorModel[i][j]);
+
+			}
+			else {
+				if(g_bAbsorptionEnable==TRUE){
+					//model update
+					T_ModelConstruction(g_nTextureTrainVolRange,fLearningRate,g_aXYZFrame,center,g_aNeighborDirection[i][j],g_TCacheBook[i][j]);
+					C_CodebookConstruction(g_aXYZFrame[i][j],j,i,g_nColorTrainVolRange,fLearningRate,g_CCacheBook[i][j]);
+
+					//clearing non-essential codewords
+					T_Absorption(g_iAbsortionPeriod,center,g_aTContinuousCnt,g_aTReferredIndex,g_TextureModel[i][j],g_TCacheBook[i][j]);
+					C_Absorption(g_iAbsortionPeriod,center,g_aCContinuousCnt,g_aCReferredIndex,g_ColorModel[i][j],g_CCacheBook[i][j]);
+
+				}
+			}
+
+			//clearing non-essential codewords for cache-books
+			if(g_bAbsorptionEnable==TRUE){
+				T_ClearNonEssentialEntriesForCachebook(g_aLandmarkArray[i][j],g_aTReferredIndex[i][j],10,g_TCacheBook[i][j]);
+				C_ClearNonEssentialEntriesForCachebook(g_aLandmarkArray[i][j],g_aCReferredIndex[i][j],10,g_CCacheBook[i][j]);
+			}
+		}
+	}
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the color based verification function											   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRange, float**aConfMap, int iNehborNum, uchar*** aXYZ, 
+												point*** aNeiDir, TextureModel**** TModel, ColorModel*** CModel, uchar**aLandmarkArr){
+	
+	int iBound_w = g_iRWidth-g_nRadius;
+	int iBound_h = g_iRHeight-g_nRadius;
+
+	for(int i=0; i<g_iRHeight; i++){
+		for(int j=0;j<g_iRWidth;j++){			
+
+			if(i<g_nRadius || i>=iBound_h || j<g_nRadius || j>=iBound_w) {
+				aLandmarkArr[i][j] = 0;
+				continue;
+			}
+
+			double tmp = aConfMap[i][j];
+			
+			if(tmp > fConfThre) aLandmarkArr[i][j] = 255;
+			else{
+				aLandmarkArr[i][j] = 0;
+				//Calculating texture amount in the background
+				double dBackAmt, dCnt;
+				dBackAmt = dCnt = 0;
+
+				for(int m=0; m<iNehborNum; m++){
+					for(int n=0;n<TModel[i][j][m]->m_iNumEntries;n++){
+						dBackAmt += TModel[i][j][m]->m_Codewords[n]->m_fMean;
+						dCnt++;
+					}
+				}
+				dBackAmt /= dCnt;
+
+				//Calculating texture amount in the input image
+				double dTemp, dInputAmt = 0;
+				for(int m=0; m<iNehborNum; m++){
+					dTemp = aXYZ[i][j][2] - aXYZ[ aNeiDir[i][j][m].m_nY ][ aNeiDir[i][j][m].m_nX ][2];
+					
+					if(dTemp>=0) dInputAmt += dTemp;
+					else dInputAmt -= dTemp;
+
+				}
+
+				//If there are only few textures in both background and input image
+				if(dBackAmt < 50 && dInputAmt <50){
+					//Conduct color codebook matching
+					BOOL bMatched = FALSE;
+					for(int m=0;m<CModel[i][j]->m_iNumEntries;m++){
+						
+						int iMatchedCount = 0;
+						for(int n=0;n<3;n++){
+							double dLowThre = CModel[i][j]->m_Codewords[m]->m_dMean[n] - nTrainVolRange - 10;
+							double dHighThre = CModel[i][j]->m_Codewords[m]->m_dMean[n] + nTrainVolRange + 10;
+
+							if(dLowThre <= aXYZ[i][j][n] && aXYZ[i][j][n] <= dHighThre) iMatchedCount++;
+						}
+
+						if(iMatchedCount==3) {
+							bMatched = TRUE;
+							break;
+						}
+
+					}
+					if(bMatched==TRUE) aLandmarkArr[i][j] = 125;
+					else aLandmarkArr[i][j] = 255;
+
+				}
+				
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//													the Gaussian filtering function								                           //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame){
+	
+	double dSigma = 0.7;
+
+	if(dSigma==0){
+		for(int i=0; i<g_iRHeight; i++){
+			for(int j=0; j<g_iRWidth; j++){
+				aFilteredFrame[i][j][0] = frame->imageData[i*frame->widthStep + j*3];
+				aFilteredFrame[i][j][1] = frame->imageData[i*frame->widthStep + j*3 + 1];
+				aFilteredFrame[i][j][2] = frame->imageData[i*frame->widthStep + j*3 + 2];
+			}
+		}
+	}
+
+	else{
+		cv::Mat temp_img(frame,TRUE);
+		cv::GaussianBlur(temp_img, temp_img, cv::Size(7,7), dSigma);
+
+		//Store results into aFilteredFrame[][][]
+		IplImage* img = &IplImage(temp_img);
+		int iWidthStep = img->widthStep;
+
+		for(int i=0; i<g_iRHeight; i++){
+			for(int j=0; j<g_iRWidth; j++){
+				aFilteredFrame[i][j][0] = img->imageData[i*img->widthStep + j*3];
+				aFilteredFrame[i][j][1] = img->imageData[i*img->widthStep + j*3 + 1];
+				aFilteredFrame[i][j][2] = img->imageData[i*img->widthStep + j*3 + 2];
+			}
+		}
+
+	}
+
+
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------//
+//														the image resize function									                 //
+//------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::ReduceImageSize(IplImage* SrcImage, IplImage* DstImage){
+
+	int iChannel = 3;
+
+	double dResizeFactor_w = (double)g_iWidth/(double)g_iRWidth;
+	double dResizeFactor_h = (double)g_iHeight/(double)g_iRHeight;
+
+
+	for(int i=0;i<g_iRHeight;i++){
+		for(int j=0;j<g_iRWidth;j++){
+			int iSrcY = (int)(i*dResizeFactor_h);
+			int iSrcX = (int)(j*dResizeFactor_w);
+
+			for(int k=0;k<iChannel;k++) DstImage->imageData[i*DstImage->widthStep + j*3 +k]
+																			= SrcImage->imageData[iSrcY*SrcImage->widthStep + iSrcX*3 + k];
+		}
+	}
+
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------//
+//											    the color space conversion function                                                   //
+//------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ){
+	
+	double dH_ratio = (2*PI)/360;
+
+	for(int i=0; i<g_iRHeight; i++){
+		
+		double dR,dG,dB;
+		double dMax, dMin;
+
+		double dH,dS, dV;
+		
+		for(int j=0;j<g_iRWidth;j++){
+
+			dB = (double)( aBGR[i][j][0] )/255;
+			dG = (double)( aBGR[i][j][1] )/255;
+			dR = (double)( aBGR[i][j][2] )/255; 
+
+
+			//Find max, min
+			dMin = MIN3(dR,dG,dB);
+			dMax = MAX3(dR,dG,dB);
+
+
+			//Get V
+			dV = dMax;
+
+			//Get S, H
+			if(dV==0) dS = dH = 0;
+			else{
+
+				//S value
+				dS = (dMax-dMin)/dMax;
+
+				if(dS == 0) dH =0;
+				else{
+					//H value
+					if(dMax == dR) {
+						dH = 60*(dG - dB)/dS;
+						if(dH < 0) dH = 360 + dH;
+					}
+					else if(dMax == dG) dH = 120 + 60*(dB - dR)/dS;
+					else dH = 240 + 60*(dR - dG)/dS;
+				}
+			}
+			dH = dH * dH_ratio;
+
+			aXYZ[i][j][0] = (uchar)( (dV * dS * cos(dH) * 127.5) + 127.5 );		//X  --> 0~255
+			aXYZ[i][j][1] = (uchar)( (dV * dS * sin(dH) * 127.5) + 127.5 );		//Y  --> 0~255
+			aXYZ[i][j][2] = (uchar)( dV * 255 );							    //Z  --> 0~255
+
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//												the function to get enlarged confidence map												   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::GetEnlargedMap(float** aOriginMap, float** aEnlargedMap){
+	int i,j;
+
+	short nSrcX;
+	short nSrcY;
+
+	double dEWweight,dNSweight;
+	double dEWtop, dEWbottom;
+
+	double dNW; //north-west
+	double dNE; //north-east
+	double dSW; //south-west
+	double dSE; //south-east
+
+	double dScaleFactor_w = ( (double)g_iWidth ) / ( (double)g_iRWidth );
+	double dScaleFactor_h = ( (double)g_iHeight ) / ( (double)g_iRHeight );
+
+	for(i=0;i<g_iHeight;i++){
+		for(j=0;j<g_iWidth;j++){
+			//backward mapping
+			nSrcY = (int)( i/dScaleFactor_h );
+			nSrcX = (int)( j/dScaleFactor_w );
+
+			if( nSrcY == (g_iRHeight-1) ) nSrcY -= 1;
+			if( nSrcX == (g_iRWidth-1) ) nSrcX -= 1;
+
+			dEWweight = i/dScaleFactor_h - nSrcY;
+			dNSweight = j/dScaleFactor_w - nSrcX;
+
+			dNW = (double)aOriginMap[nSrcY][nSrcX];
+			dNE = (double)aOriginMap[nSrcY][nSrcX+1];
+			dSW = (double)aOriginMap[nSrcY+1][nSrcX];
+			dSE = (double)aOriginMap[nSrcY+1][nSrcX+1];
+			
+			// interpolation
+			dEWtop = dNW + dEWweight * (dNE - dNW);
+			dEWbottom = dSW + dEWweight * (dSE - dSW);
+
+			aEnlargedMap[i][j] = (float)( dEWtop + dNSweight * (dEWbottom - dEWtop) );
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//										   				 the morphological operation function				    				   		   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::MorphologicalOpearions(uchar** aInput, uchar** aOutput, double dThresholdRatio, int iMaskSize, int iWidth, int iHeight){
+
+	int iOffset = (int)(iMaskSize/2);
+
+	int iBound_w = iWidth-iOffset;
+	int iBound_h = iHeight-iOffset;
+
+	uchar** aTemp = (uchar**)malloc(sizeof(uchar*)*iHeight);
+	for(int i=0;i<iHeight;i++){
+		aTemp[i] = (uchar*)malloc(sizeof(uchar)*iWidth);
+	}
+
+	for(int i=0;i<iHeight;i++){
+		for(int j=0;j<iWidth;j++){
+			aTemp[i][j] = aInput[i][j];
+		}
+	}
+
+	int iThreshold = (int)(iMaskSize*iMaskSize*dThresholdRatio);
+	for(int i=0;i<iHeight;i++){
+		for(int j=0;j<iWidth;j++){
+
+			if(i<iOffset || i>=iBound_h || j<iOffset || j>=iBound_w){
+				aOutput[i][j] = 0;
+				continue;
+			}
+
+			int iCnt = 0;
+			for(int m=-iOffset;m<=iOffset;m++){
+				for(int n=-iOffset;n<=iOffset;n++){
+					if(aTemp[i+m][j+n]==255) iCnt++;
+				}
+			}
+
+			if(iCnt >= iThreshold) aOutput[i][j] = 255;
+			else aOutput[i][j] = 0;
+		}
+	}
+
+
+	for(int i=0;i<iHeight;i++){
+		free(aTemp[i]);
+	}
+	free(aTemp);
+
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//													2-raster scan pass based labeling function											   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::Labeling(uchar** aBinaryArray,int* pLabelCount, int** aLabelTable){
+	int x,y,i;		// pass 1,2
+	int cnt=0;		// pass 1
+	int label=0;	// pass 2
+
+	int iSize = g_iRWidth * g_iRHeight;
+	int iTableSize = iSize/2;
+
+	// initialize , table1 table1
+	int* aPass1 = (int*)malloc(iSize * sizeof(int));
+	int* aTable1 = (int*)malloc(iSize/2 * sizeof(int));
+	int* aTable2 = (int*)malloc(iSize/2 * sizeof(int));
+
+	memset(aPass1, 0, (iSize)* sizeof(int));
+	for (y=1; y < (g_iRHeight); y++){
+		for (x = 1; x < (g_iRWidth); x++){
+			aLabelTable[y][x] = 0;
+		}
+	}
+
+	for(i=0; i < iTableSize; i++){
+		aTable1[i] = i;
+	}
+	memset(aTable2, 0, iTableSize * sizeof(int));
+
+	// pass 1
+	for (y=1; y < (g_iRHeight); y++){
+		for (x = 1; x < (g_iRWidth); x++){
+
+			if (aBinaryArray[y][x] == 255){ // fore ground??
+				int up, le;
+
+				up = aPass1[ (y-1)*(g_iRWidth) + (x  ) ]; // up  index
+				le = aPass1[ (y  )*(g_iRWidth) + (x-1) ]; // left index
+
+				// case
+				if( up == 0 && le == 0){
+					++cnt;
+					aPass1[ y * g_iRWidth + x ] = cnt;
+
+				}else if( up != 0 && le != 0){
+					if ( up > le){
+						aPass1[ y *g_iRWidth + x ] = le;
+						aTable1[up] = aTable1[le]; // update table1 table1
+					}else{
+						aPass1[ y * g_iRWidth + x ] = up;
+						aTable1[le] = aTable1[up]; // update table1 table1
+					}
+				}else{
+					aPass1[ y * g_iRWidth + x ] = up + le;
+				}
+
+			}
+
+		}
+	}
+
+	// pass 2
+	for (y=1; y < (g_iRHeight); y++){
+		for (x = 1; x < (g_iRWidth); x++){
+
+			if (aPass1[ y * g_iRWidth + x]){
+				int v =  aTable1[aPass1[ y * g_iRWidth + x]];
+
+				if ( aTable2[v]  == 0){
+					++label;
+					aTable2[v] = label;
+				}
+
+				aLabelTable[y][x] = aTable2[v];
+			}
+		}
+	}
+
+	*pLabelCount = label;
+
+	free(aPass1);
+	free(aTable1);
+	free(aTable2);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//									the function to set bounding boxes for each candidate foreground regions					    	   //																									   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::SetBoundingBox(int iLabelCount, int** aLabelTable){
+	int iBoundBoxIndex;
+
+	g_BoundBoxInfo->m_iBoundBoxNum = iLabelCount;
+
+	for (int i=0; i<g_BoundBoxInfo->m_iBoundBoxNum; i++ ){
+		g_BoundBoxInfo->m_aRLeft[i] = 9999;		//left
+		g_BoundBoxInfo->m_aRUpper[i] = 9999;	//top
+		g_BoundBoxInfo->m_aRRight[i] = 0;		//right
+		g_BoundBoxInfo->m_aRBottom[i] = 0;		//bottom
+	}
+
+	//Step1: Set tight bounding boxes
+	for(int i=1;i<g_iRHeight;i++){
+		for(int j=1;j<g_iRWidth;j++){
+			
+			if(   (aLabelTable[i][j]==0) ) continue;
+
+			iBoundBoxIndex = aLabelTable[i][j]-1;
+
+			if( g_BoundBoxInfo->m_aRLeft[ iBoundBoxIndex ] > j ) g_BoundBoxInfo->m_aRLeft[ iBoundBoxIndex ] = j;		//left
+			if( g_BoundBoxInfo->m_aRUpper[ iBoundBoxIndex ] > i ) g_BoundBoxInfo->m_aRUpper[ iBoundBoxIndex ] = i;		//top
+			if( g_BoundBoxInfo->m_aRRight[ iBoundBoxIndex ] < j ) g_BoundBoxInfo->m_aRRight[ iBoundBoxIndex ] = j;		//right
+			if( g_BoundBoxInfo->m_aRBottom[ iBoundBoxIndex ] < i ) g_BoundBoxInfo->m_aRBottom[ iBoundBoxIndex ] = i;	//bottom
+
+		}
+	}
+
+	//Step2: Add margins.
+	int iBoundary_w = (int)(g_iRWidth / 80), iBoundary_h = (int)(g_iRHeight / 60);
+
+	for( int i=0; i<g_BoundBoxInfo->m_iBoundBoxNum; i++ ){	
+
+		g_BoundBoxInfo->m_aRLeft[i] -= iBoundary_w;
+		if(g_BoundBoxInfo->m_aRLeft[i] < g_nRadius) g_BoundBoxInfo->m_aRLeft[i] = g_nRadius;									//left
+
+		g_BoundBoxInfo->m_aRRight[i] += iBoundary_w;
+		if(g_BoundBoxInfo->m_aRRight[i] >= g_iRWidth-g_nRadius) g_BoundBoxInfo->m_aRRight[i] = g_iRWidth-g_nRadius-1;		    //Right
+
+		g_BoundBoxInfo->m_aRUpper[i] -= iBoundary_h;
+		if(g_BoundBoxInfo->m_aRUpper[i] < g_nRadius) g_BoundBoxInfo->m_aRUpper[i] = g_nRadius;									//Top
+
+		g_BoundBoxInfo->m_aRBottom[i] += iBoundary_h;
+		if(g_BoundBoxInfo->m_aRBottom[i] >= g_iRHeight-g_nRadius) g_BoundBoxInfo->m_aRBottom[i] =g_iRHeight-g_nRadius-1;	
+	}
+
+	double dH_ratio = (double)g_iHeight/(double)g_iRHeight;
+	double dW_ratio = (double)g_iWidth/(double)g_iRWidth;
+
+	for(int i=0;i<g_BoundBoxInfo->m_iBoundBoxNum;i++){
+		g_BoundBoxInfo->m_aLeft[i] = (int)(g_BoundBoxInfo->m_aRLeft[i] * dW_ratio);
+		g_BoundBoxInfo->m_aUpper[i] = (int)(g_BoundBoxInfo->m_aRUpper[i] * dH_ratio);
+		g_BoundBoxInfo->m_aRight[i] = (int)(g_BoundBoxInfo->m_aRRight[i] * dW_ratio);
+		g_BoundBoxInfo->m_aBottom[i] = (int)(g_BoundBoxInfo->m_aRBottom[i] * dH_ratio);
+	}
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the box verification function													   //																							   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::BoundBoxVerification(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo){
+	
+	//Step1: Verification by the bounding box size
+	EvaluateBoxSize(BoundBoxInfo);
+
+	//Step2: Verification by checking whether the region is ghost
+	EvaluateGhostRegion(frame, aResForeMap, BoundBoxInfo);
+
+	//Step3: Counting the # of valid box
+	g_iForegroundNum = 0;
+	for( int i=0; i<BoundBoxInfo->m_iBoundBoxNum; i++ ){
+		if(BoundBoxInfo->m_ValidBox[i] == TRUE) g_iForegroundNum++;
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//																the size based verification												   //																							   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::EvaluateBoxSize(BoundingBoxInfo* BoundBoxInfo){
+
+	//Set thresholds
+	int iLowThreshold_w, iHighThreshold_w;	
+	iLowThreshold_w = g_iRWidth / 32; if(iLowThreshold_w<5) iLowThreshold_w = 5;
+	iHighThreshold_w = g_iRWidth;
+
+	int iLowThreshold_h, iHighThreshold_h;  
+	iLowThreshold_h = g_iRHeight / 24; if(iLowThreshold_h<5) iLowThreshold_h = 5;
+	iHighThreshold_h = g_iRHeight;
+
+	int iBoxWidth,iBoxHeight;
+	
+	//Perform verification.
+	for( int i=0; i<BoundBoxInfo->m_iBoundBoxNum; i++ ){
+
+		iBoxWidth = BoundBoxInfo->m_aRRight[i] - BoundBoxInfo->m_aRLeft[i];
+		iBoxHeight = BoundBoxInfo->m_aRBottom[i] - BoundBoxInfo->m_aRUpper[i];	
+
+		if(iLowThreshold_w<=iBoxWidth && iBoxWidth<=iHighThreshold_w && iLowThreshold_h<=iBoxHeight && iBoxHeight<= iHighThreshold_h) {
+			BoundBoxInfo->m_ValidBox[i] = TRUE;
+		}
+		else BoundBoxInfo->m_ValidBox[i] = FALSE;
+	}
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------//
+//														overlapped region removal													  //
+//------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo){
+
+	BOOL *aValidBoxFlag = new BOOL[SrcBoxInfo->m_iBoundBoxNum];
+	for(int i=0;i<SrcBoxInfo->m_iBoundBoxNum;i++) aValidBoxFlag[i] = TRUE;
+
+	int size1, size2;
+	short *aLeft=SrcBoxInfo->m_aRLeft, *aRight=SrcBoxInfo->m_aRRight;
+	short *aTop=SrcBoxInfo->m_aRUpper, *aBottom=SrcBoxInfo->m_aRBottom;
+
+	int iThreshold,iCount, iSmall_Idx, iLarge_Idx;
+	double dThreRatio = 0.7;
+
+	for(int i=0;i<SrcBoxInfo->m_iBoundBoxNum;i++){
+	
+		if(SrcBoxInfo->m_ValidBox[i]==FALSE) {
+			aValidBoxFlag[i] = FALSE;
+			continue;
+		}
+
+		size1 = (aRight[i] - aLeft[i]) * (aBottom[i] - aTop[i]);
+
+		for(int j=i;j<SrcBoxInfo->m_iBoundBoxNum;j++){
+			if( (i==j) || (SrcBoxInfo->m_ValidBox[j]==FALSE) ) continue;
+
+			//Setting threshold for checking overlapped region size
+			size2 = (aRight[j] - aLeft[j]) * (aBottom[j] - aTop[j]);
+
+			if(size1 >= size2) {
+				iThreshold = (int)( size2 * dThreRatio );
+				iSmall_Idx = j; iLarge_Idx = i;
+			}
+			else {
+				iThreshold = (int)( size1 * dThreRatio );
+				iSmall_Idx= i; iLarge_Idx = j;
+			}
+			
+			//Calculating overlapped region size
+			iCount = 0;
+			for(int m=aLeft[iSmall_Idx]; m<aRight[iSmall_Idx]; m++){
+				for(int n=aTop[iSmall_Idx]; n<aBottom[iSmall_Idx]; n++){
+					if( aLeft[iLarge_Idx]<=m && m<=aRight[iLarge_Idx] && aTop[iLarge_Idx]<=n && n<=aBottom[iLarge_Idx]) iCount++;
+				}
+			}
+
+			//Evaluating overlapped region size
+			if(iCount > iThreshold) aValidBoxFlag[iSmall_Idx] = FALSE;
+		}
+	}
+
+	for(int i=0;i<SrcBoxInfo->m_iBoundBoxNum;i++) SrcBoxInfo->m_ValidBox[i] = aValidBoxFlag[i];	
+	delete[] aValidBoxFlag;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														appearance based verification													   //																							   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo){
+
+	double dThreshold = 10;
+
+	BOOL** aUpdateMap = (BOOL**)malloc(sizeof(BOOL*)*g_iRHeight);
+	for(int i=0;i<g_iRHeight;i++){
+		aUpdateMap[i] = (BOOL*)malloc(sizeof(BOOL)*g_iRWidth);
+		for(int j=0;j<g_iRWidth;j++) aUpdateMap[i][j] = FALSE;
+	}
+
+	//Step1: Conduct fore-region evaluation to identify ghost regions
+
+	for(int i=0; i<BoundBoxInfo->m_iBoundBoxNum; i++){
+		if(BoundBoxInfo->m_ValidBox[i]==TRUE){
+			int iWin_w = BoundBoxInfo->m_aRRight[i] - BoundBoxInfo->m_aRLeft[i];
+			int iWin_h = BoundBoxInfo->m_aRBottom[i] - BoundBoxInfo->m_aRUpper[i];
+
+			//Generating edge image from bound-boxed frame region
+			IplImage* resized_frame = cvCreateImage(cvSize(g_iRWidth,g_iRHeight),IPL_DEPTH_8U,3);
+			cvResize(frame,resized_frame,CV_INTER_NN);
+
+			cvSetImageROI(resized_frame, cvRect(BoundBoxInfo->m_aRLeft[i], BoundBoxInfo->m_aRUpper[i], iWin_w, iWin_h));
+			IplImage* edge_frame = cvCreateImage(cvSize(iWin_w,iWin_h),IPL_DEPTH_8U,1);
+
+			cvCvtColor(resized_frame,edge_frame,CV_BGR2GRAY);
+			cvResetImageROI(resized_frame);
+
+			cvCanny(edge_frame,edge_frame,100,150);
+
+			//Generating edge image from aResForeMap
+			IplImage* edge_fore = cvCreateImage(cvSize(iWin_w,iWin_h),IPL_DEPTH_8U,1);
+			for(int m=BoundBoxInfo->m_aRUpper[i]; m<BoundBoxInfo->m_aRBottom[i]; m++){
+				for(int n=BoundBoxInfo->m_aRLeft[i]; n<BoundBoxInfo->m_aRRight[i]; n++){
+					edge_fore->imageData[(m-BoundBoxInfo->m_aRUpper[i])*edge_fore->widthStep + (n-BoundBoxInfo->m_aRLeft[i])] = (char)aResForeMap[m][n];
+				}
+			}
+			cvCanny(edge_fore,edge_fore,100,150);
+			//Calculating partial undirected Hausdorff distance
+			double distance = CalculateHausdorffDist(edge_frame,edge_fore);
+			
+			//Recording evaluation result
+			if(distance > dThreshold) {
+				
+				for(int m=BoundBoxInfo->m_aRUpper[i]; m<BoundBoxInfo->m_aRBottom[i]; m++){
+					for(int n=BoundBoxInfo->m_aRLeft[i]; n<BoundBoxInfo->m_aRRight[i]; n++){
+						aUpdateMap[m][n] = TRUE;
+					}
+				}
+				
+				BoundBoxInfo->m_ValidBox[i]=FALSE;		
+			}
+
+			cvReleaseImage(&resized_frame);
+			cvReleaseImage(&edge_frame);
+			cvReleaseImage(&edge_fore);
+		}
+	}
+
+	//Step2: Adding information fo ghost region pixels to background model
+	float fLearningRate = g_fLearningRate;
+	
+	for(int i=0;i<g_iRHeight;i++){
+		for(int j=0;j<g_iRWidth;j++){
+			if(aUpdateMap[i][j]==TRUE){
+				point center;
+				center.m_nX=j; center.m_nY=i;
+
+				T_ModelConstruction(g_nTextureTrainVolRange,fLearningRate,g_aXYZFrame,center,g_aNeighborDirection[i][j],g_TextureModel[i][j]);
+				C_CodebookConstruction(g_aXYZFrame[i][j],j,i,g_nColorTrainVolRange,fLearningRate,g_ColorModel[i][j]);
+
+				T_ClearNonEssentialEntries(g_iBackClearPeriod,g_TextureModel[i][j]);
+				C_ClearNonEssentialEntries(g_iBackClearPeriod,g_ColorModel[i][j]);
+
+			}
+		}
+	}
+
+	for(int i=0;i<g_iRHeight;i++) free(aUpdateMap[i]);
+	free(aUpdateMap);
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//								the function to calculate partial undirected Hausdorff distance(forward distance)						   //																							   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+double SJN_MultiCueBGS::CalculateHausdorffDist(IplImage* input_image, IplImage* model_image){
+
+	//Step1: Generating imag vectors
+	//For reduce errors, points at the image boundary are excluded
+	vector<point> vInput, vModel;
+	point temp;
+
+	//input image --> input vector 
+	for(int i=0;i<input_image->height;i++){
+		for(int j=0;j<input_image->width;j++){
+
+			if( (uchar)input_image->imageData[i*input_image->widthStep + j]==0 ) continue;
+
+			temp.m_nX = j; temp.m_nY = i;
+			vInput.push_back(temp);
+		}
+	}
+	//model image --> model vector
+	for(int i=0; i<model_image->height; i++){
+		for(int j=0; j<model_image->width; j++){
+			if( (uchar)model_image->imageData[i*model_image->widthStep + j]==0 ) continue;
+
+			temp.m_nX = j; temp.m_nY = i;	
+			vModel.push_back(temp);
+		}
+	}
+
+	if( vInput.size()==0 && vModel.size()!=0 ) return (double)vModel.size();
+	else if( vInput.size()!=0 && vModel.size()==0 ) return (double)vInput.size();
+	else if( vInput.size()==0 && vModel.size()==0) return 0.0;
+
+	//Step2: Calculating forward distance h(Model,Image)
+	double dDist, temp1, temp2, dMinDist;
+	vector<double> vTempDist;
+
+	for( auto iter_m=vModel.begin(); iter_m<vModel.end(); iter_m++ ){
+
+		dMinDist = 9999999;
+		for( auto iter_i=vInput.begin(); iter_i<vInput.end(); iter_i++){
+			temp1 = (*iter_m).m_nX - (*iter_i).m_nX;
+			temp2 = (*iter_m).m_nY - (*iter_i).m_nY;
+			dDist = temp1*temp1 + temp2*temp2;
+
+			if(dDist < dMinDist) dMinDist = dDist;
+		}
+		vTempDist.push_back(dMinDist);
+	}
+	sort(vTempDist.begin(), vTempDist.end()); //in ascending order
+
+	double dQuantileVal = 0.9, dForwardDistance;
+	int iDistIndex = (int)(dQuantileVal*vTempDist.size()); if(iDistIndex == vTempDist.size()) iDistIndex -= 1;
+
+	dForwardDistance = sqrt( vTempDist[ iDistIndex ] );
+	return dForwardDistance;
+
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//											function to remove non-valid bounding boxes fore fore-candidates							   //												
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo){
+
+	int iBoxNum = BoundBoxInfo->m_iBoundBoxNum;
+
+	for(int k=0;k<iBoxNum; k++){
+		
+		if(BoundBoxInfo->m_ValidBox[k]==FALSE){
+			for(int i=BoundBoxInfo->m_aRUpper[k]; i<BoundBoxInfo->m_aRBottom[k]; i++){
+				for(int j=BoundBoxInfo->m_aRLeft[k]; j<BoundBoxInfo->m_aRRight[k]; j++){
+					if(aResForeMap[i][j]==255) aResForeMap[i][j] = 0;
+				}
+			}
+		}
+
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//													the function returning a foreground binary-map										   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::GetForegroundMap(IplImage* return_image, IplImage* input_frame){
+	
+	if(g_bForegroundMapEnable == FALSE) return;
+	
+	IplImage* temp_image = cvCreateImage(cvSize(g_iRWidth,g_iRHeight),IPL_DEPTH_8U,3);
+
+	if(input_frame==NULL){
+		for(int i=0;i<g_iRHeight;i++){
+			for(int j=0;j<g_iRWidth;j++){
+				temp_image->imageData[i*temp_image->widthStep + j*3] = (char)g_aResizedForeMap[i][j];
+				temp_image->imageData[i*temp_image->widthStep + j*3 + 1] = (char)g_aResizedForeMap[i][j];
+				temp_image->imageData[i*temp_image->widthStep + j*3 + 2] = (char)g_aResizedForeMap[i][j];
+			}
+		}
+	}
+
+	else{
+
+		cvResize(input_frame,temp_image);
+		CvScalar MixColor;
+		MixColor.val[0] = 255;	//B
+		MixColor.val[1] = 0;	//G
+		MixColor.val[2] = 255;   //R
+
+		for(int i=0;i<g_iRHeight;i++){
+			for(int j=0;j<g_iRWidth;j++){
+				
+				if(g_aResizedForeMap[i][j]==255) {
+
+					uchar B = (uchar)temp_image->imageData[i*temp_image->widthStep + j*3];
+					uchar G = (uchar)temp_image->imageData[i*temp_image->widthStep + j*3];
+					uchar R = (uchar)temp_image->imageData[i*temp_image->widthStep + j*3];
+
+					B = (uchar)(B*0.45 + MixColor.val[0]*0.55);
+					G = (uchar)(G*0.45 + MixColor.val[1]*0.55);
+					R = (uchar)(R*0.45 + MixColor.val[2]*0.55);
+
+					temp_image->imageData[i*temp_image->widthStep + j*3] = (char)B;
+					temp_image->imageData[i*temp_image->widthStep + j*3 + 1] = (char)G;
+					temp_image->imageData[i*temp_image->widthStep + j*3 + 2] = (char)R;
+				}
+			}
+		}
+	}
+
+	cvResize(temp_image,return_image);
+
+	cvReleaseImage(&temp_image);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//												the	initialization function for the texture-models									       //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_AllocateTextureModelRelatedMemory(){
+	int i,j,k; 
+
+	//neighborhood system related
+	int iMaxNeighborArraySize = 8;
+	g_aNeighborDirection = (point***)malloc(sizeof(point**)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++){
+		g_aNeighborDirection[i] = (point**)malloc(sizeof(point*)*g_iRWidth);
+		for(j=0;j<g_iRWidth;j++){
+			g_aNeighborDirection[i][j] = (point*)malloc(sizeof(point)*iMaxNeighborArraySize);
+		}
+	}
+	T_SetNeighborDirection(g_aNeighborDirection);
+
+	//texture-model related
+	int iElementArraySize = 6;
+	g_TextureModel = (TextureModel****)malloc(sizeof(TextureModel***)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++){
+		g_TextureModel[i] = (TextureModel***)malloc(sizeof(TextureModel**)*g_iRWidth);
+		for(j=0;j<g_iRWidth;j++){
+			g_TextureModel[i][j] = (TextureModel**)malloc(sizeof(TextureModel*)*g_nNeighborNum);
+			for(k=0;k<g_nNeighborNum;k++){
+				g_TextureModel[i][j][k] = (TextureModel*)malloc(sizeof(TextureModel));
+				g_TextureModel[i][j][k]->m_Codewords = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*iElementArraySize);
+				g_TextureModel[i][j][k]->m_iElementArraySize = iElementArraySize;
+				g_TextureModel[i][j][k]->m_iNumEntries = 0;
+				g_TextureModel[i][j][k]->m_iTotal = 0;
+				g_TextureModel[i][j][k]->m_bID = 1;
+			}
+		}
+	}
+
+	g_aTextureConfMap = (float**)malloc(sizeof(float*)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++) g_aTextureConfMap[i] = (float*)malloc(sizeof(float)*g_iRWidth);
+
+	//cache-book related
+	if(g_bAbsorptionEnable==TRUE){
+		iElementArraySize = iElementArraySize/2;
+		if(iElementArraySize<3)iElementArraySize = 3;
+		
+		g_TCacheBook = (TextureModel****)malloc(sizeof(TextureModel***)*g_iRHeight);
+		for(i=0;i<g_iRHeight;i++){
+			g_TCacheBook[i] = (TextureModel***)malloc(sizeof(TextureModel**)*g_iRWidth);
+			for(j=0;j<g_iRWidth;j++){
+				g_TCacheBook[i][j] = (TextureModel**)malloc(sizeof(TextureModel*)*g_nNeighborNum);
+				for(k=0;k<g_nNeighborNum;k++){
+					g_TCacheBook[i][j][k] = (TextureModel*)malloc(sizeof(TextureModel));
+					g_TCacheBook[i][j][k]->m_Codewords = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*iElementArraySize);
+					g_TCacheBook[i][j][k]->m_iElementArraySize = iElementArraySize;
+					g_TCacheBook[i][j][k]->m_iNumEntries = 0;
+					g_TCacheBook[i][j][k]->m_iTotal = 0;
+					g_TCacheBook[i][j][k]->m_bID = 0;
+				}
+			}
+		}
+
+		g_aTReferredIndex = (short***)malloc(sizeof(short**)*g_iRHeight);
+		g_aTContinuousCnt = (short***)malloc(sizeof(short**)*g_iRHeight);
+		for(i=0;i<g_iRHeight;i++){
+			g_aTReferredIndex[i] = (short**)malloc(sizeof(short*)*g_iRWidth);
+			g_aTContinuousCnt[i] = (short**)malloc(sizeof(short*)*g_iRWidth);
+			for(j=0;j<g_iRWidth;j++) {
+				g_aTReferredIndex[i][j] = (short*)malloc(sizeof(short)*g_nNeighborNum);
+				g_aTContinuousCnt[i][j] = (short*)malloc(sizeof(short)*g_nNeighborNum);
+				for(k=0;k<g_nNeighborNum;k++){
+					g_aTReferredIndex[i][j][k] = -1;
+					g_aTContinuousCnt[i][j][k] = 0; 
+				}
+			}
+		}
+	}
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//															the memory release function											           //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_ReleaseTextureModelRelatedMemory(){
+	int i,j,k,m;
+	short nNeighborNum = g_nNeighborNum; 
+
+	for(i=0;i<g_iRHeight;i++){
+		for(j=0;j<g_iRWidth;j++){
+			for(k=0;k<nNeighborNum;k++){
+				for(m=0;m<g_TextureModel[i][j][k]->m_iNumEntries;m++) free(g_TextureModel[i][j][k]->m_Codewords[m]);
+				free(g_TextureModel[i][j][k]->m_Codewords);
+				free(g_TextureModel[i][j][k]);
+			}
+			free(g_TextureModel[i][j]);
+		}free(g_TextureModel[i]);
+	}
+	free(g_TextureModel);
+
+	for(i=0;i<g_iRHeight;i++){
+		for(j=0;j<g_iRWidth;j++) free(g_aNeighborDirection[i][j]);
+		free(g_aNeighborDirection[i]);
+	}
+	free(g_aNeighborDirection);
+
+	for(i=0;i<g_iRHeight;i++) free(g_aTextureConfMap[i]);
+	free(g_aTextureConfMap);
+
+	if(g_bAbsorptionEnable==TRUE){
+		for(i=0;i<g_iRHeight;i++){
+			for(j=0;j<g_iRWidth;j++){
+				for(k=0;k<nNeighborNum;k++){
+					for(m=0;m<g_TCacheBook[i][j][k]->m_iNumEntries;m++) free(g_TCacheBook[i][j][k]->m_Codewords[m]);
+					free(g_TCacheBook[i][j][k]->m_Codewords);
+					free(g_TCacheBook[i][j][k]);
+				}
+				free(g_TCacheBook[i][j]);
+			}free(g_TCacheBook[i]);
+		}
+		free(g_TCacheBook);
+
+		for(i=0;i<g_iRHeight;i++){
+			for(j=0;j<g_iRWidth;j++){
+				free(g_aTReferredIndex[i][j]);
+				free(g_aTContinuousCnt[i][j]);
+			}
+			free(g_aTReferredIndex[i]);
+			free(g_aTContinuousCnt[i]);
+		}
+		free(g_aTReferredIndex);
+		free(g_aTContinuousCnt);
+
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the codebook construction function				                                   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange,float fLearningRate, uchar*** aXYZ,point center, point* aNei, TextureModel** aModel){
+	
+	int i,j;
+	int iMatchedIndex;
+
+	short nNeighborNum = g_nNeighborNum;
+
+	float fDifference;
+	float fDiffMean;
+
+	float fNegLearningRate = 1-fLearningRate;
+
+	//for all neighboring pairs 
+	for(i=0;i<nNeighborNum;i++){
+		
+		fDifference = (float)(aXYZ[center.m_nY][center.m_nX][2] - aXYZ[aNei[i].m_nY][aNei[i].m_nX][2]);
+
+		//Step1: matching
+		iMatchedIndex = -1;
+		for(j=0;j<aModel[i]->m_iNumEntries;j++){
+			if(aModel[i]->m_Codewords[j]->m_fLowThre  <= fDifference && fDifference <= aModel[i]->m_Codewords[j]->m_fHighThre){
+				iMatchedIndex = j;
+				break;
+			}
+		}
+			
+		aModel[i]->m_iTotal++;
+		//Step2: adding a new element
+		if(iMatchedIndex == -1){
+			//element array�� Ȯ���� �ʿ䰡 ������ Ȯ��
+			if(aModel[i]->m_iElementArraySize == aModel[i]->m_iNumEntries){
+				aModel[i]->m_iElementArraySize += 5;
+				TextureCodeword **temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*aModel[i]->m_iElementArraySize);
+				for(j=0;j<aModel[i]->m_iNumEntries;j++){
+					temp[j] = aModel[i]->m_Codewords[j];
+					aModel[i]->m_Codewords[j] = NULL;
+				}
+				free(aModel[i]->m_Codewords);
+				aModel[i]->m_Codewords = temp;
+			}
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries] = (TextureCodeword*)malloc(sizeof(TextureCodeword));
+
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_fMean  = fDifference;
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_fLowThre  = aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_fMean  - nTrainVolRange;
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_fHighThre = aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_fMean  + nTrainVolRange;
+
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_iT_first_time = aModel[i]->m_iTotal;
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_iT_last_time = aModel[i]->m_iTotal;
+			aModel[i]->m_Codewords[aModel[i]->m_iNumEntries]->m_iMNRL = aModel[i]->m_iTotal-1;
+			aModel[i]->m_iNumEntries ++;
+		}
+
+		//Step3: update
+		else{
+			fDiffMean = aModel[i]->m_Codewords[iMatchedIndex]->m_fMean;
+			aModel[i]->m_Codewords[iMatchedIndex]->m_fMean  = fLearningRate*fDifference + fNegLearningRate*fDiffMean;
+
+			aModel[i]->m_Codewords[iMatchedIndex]->m_fLowThre  = aModel[i]->m_Codewords[iMatchedIndex]->m_fMean  - nTrainVolRange;
+			aModel[i]->m_Codewords[iMatchedIndex]->m_fHighThre = aModel[i]->m_Codewords[iMatchedIndex]->m_fMean  + nTrainVolRange;
+
+			aModel[i]->m_Codewords[iMatchedIndex]->m_iT_last_time = aModel[i]->m_iTotal;	
+		}
+
+		//cache-book handling
+		if(aModel[i]->m_bID==1){
+			//1. m_iMNRL update
+			int negTime;
+			for(j=0;j<aModel[i]->m_iNumEntries;j++){
+				//m_iMNRL update
+				negTime = aModel[i]->m_iTotal - aModel[i]->m_Codewords[j]->m_iT_last_time + aModel[i]->m_Codewords[j]->m_iT_first_time - 1;
+				if(aModel[i]->m_Codewords[j]->m_iMNRL < negTime) aModel[i]->m_Codewords[j]->m_iMNRL = negTime;
+			}
+			
+
+			//2. g_aTReferredIndex[center.m_nY][center.m_nX][i] update
+			if(g_bAbsorptionEnable == TRUE) g_aTReferredIndex[center.m_nY][center.m_nX][i] = -1;
+		}
+		
+		else{
+			//1. m_iMNRL update
+			if(iMatchedIndex == -1) aModel[i]->m_Codewords[aModel[i]->m_iNumEntries-1]->m_iMNRL = 0;
+
+			//2. g_aTReferredIndex[center.m_nY][center.m_nX][i] update
+			if(iMatchedIndex==-1){
+				g_aTReferredIndex[center.m_nY][center.m_nX][i] = aModel[i]->m_iNumEntries-1;
+				g_aTContinuousCnt[center.m_nY][center.m_nX][i] = 1;
+			}
+			else{
+				if(iMatchedIndex == g_aTReferredIndex[center.m_nY][center.m_nX][i]) g_aTContinuousCnt[center.m_nY][center.m_nX][i]++;
+				else{
+					g_aTReferredIndex[center.m_nY][center.m_nX][i] = iMatchedIndex;
+					g_aTContinuousCnt[center.m_nY][center.m_nX][i] = 1;
+				}
+			}
+		}
+
+	}
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//												Clear non-essential codewords of the given codebook						                   //																									   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_ClearNonEssentialEntries(short nClearNum, TextureModel** aModel){
+	int i,n;
+	int iStaleThresh = (int)(nClearNum*0.5);
+	int iKeepCnt;
+	int* aKeep;
+
+	short nNeighborNum = g_nNeighborNum;
+
+	TextureModel* c;
+
+	for(n=0;n<nNeighborNum;n++){
+		c = aModel[n];
+
+		if(c->m_iTotal < nClearNum) continue; //(being operated only when c[w][h]->m_iTotal == nClearNum)
+
+		//Step1: initialization
+		aKeep = (int*)malloc(sizeof(int)*c->m_iNumEntries);
+
+		iKeepCnt = 0;
+
+		//Step2: Find non-essential code-words
+		for(i=0;i<c->m_iNumEntries;i++){
+			if(c->m_Codewords[i]->m_iMNRL > iStaleThresh) {
+				aKeep[i] = 0; //removal candidate
+			}
+			else {
+				aKeep[i] = 1; 
+				iKeepCnt++;
+			}
+		}
+
+		//Step3: Perform removal
+		if(iKeepCnt==0 || iKeepCnt==c->m_iNumEntries){
+			for(i=0;i<c->m_iNumEntries;i++){
+				c->m_Codewords[i]->m_iT_first_time = 1;
+				c->m_Codewords[i]->m_iT_last_time = 1;
+				c->m_Codewords[i]->m_iMNRL = 0;
+			}
+		}
+
+		else{
+			iKeepCnt = 0;
+			TextureCodeword** temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*c->m_iNumEntries);
+
+			for(i=0;i<c->m_iNumEntries;i++){
+				if(aKeep[i] == 1){
+					temp[iKeepCnt] = c->m_Codewords[i];
+					temp[iKeepCnt]->m_iT_first_time = 1;
+					temp[iKeepCnt]->m_iT_last_time = 1;
+					temp[iKeepCnt]->m_iMNRL = 0;
+					iKeepCnt++;
+				}
+				else free(c->m_Codewords[i]);
+			}
+
+			//ending..
+			free(c->m_Codewords);
+			c->m_Codewords = temp;
+			c->m_iElementArraySize = c->m_iNumEntries;
+			c->m_iNumEntries = iKeepCnt;
+		}
+		c->m_iTotal=0;
+		free(aKeep);
+
+	}
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//								Clear non-essential codewords of the given codebook (only for the cache-book)			                   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short* nReferredIdxArr, short nClearNum, TextureModel** pCachebook){
+	int i,n;
+	short nNeighborNum = g_nNeighborNum;
+
+	TextureModel* c;
+	short nReferredIdx;
+
+	for(n=0;n<nNeighborNum;n++){
+
+		c = pCachebook[n];
+		nReferredIdx = nReferredIdxArr[n];
+	
+		//pCachebook->m_iTotal < nClearNum? --> MNRL update
+		if(c->m_iTotal<nClearNum) {
+			for(i=0;i<c->m_iNumEntries;i++){
+				if(bLandmark == 255 && i == nReferredIdx) c->m_Codewords[i]->m_iMNRL = 0;
+				else c->m_Codewords[i]->m_iMNRL++;
+			}
+
+			c->m_iTotal++;
+		}
+
+		//Perform clearing
+		else{
+			int iStaleThreshold = 5;
+
+			int* aKeep;
+			short nKeepCnt;
+
+			aKeep = (int*)malloc(sizeof(int)*c->m_iNumEntries);
+			nKeepCnt = 0;
+
+			for(i=0;i<c->m_iNumEntries;i++){
+				if(c->m_Codewords[i]->m_iMNRL<iStaleThreshold){
+					aKeep[i] = 1;
+					nKeepCnt++;
+				}
+				else aKeep[i] = 0;
+			}
+
+			c->m_iElementArraySize = nKeepCnt+2;
+			if(c->m_iElementArraySize<3) c->m_iElementArraySize = 3;
+
+			TextureCodeword** temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*c->m_iElementArraySize);
+			nKeepCnt = 0;
+
+			for(i=0;i<c->m_iNumEntries;i++){
+				if(aKeep[i]==1){
+					temp[nKeepCnt] = c->m_Codewords[i];
+					temp[nKeepCnt]->m_iMNRL = 0;
+					nKeepCnt++;
+				}
+				else {
+					free(c->m_Codewords[i]);
+				}
+
+			}
+
+			//ending..
+			free(c->m_Codewords);
+			c->m_Codewords = temp;
+			c->m_iNumEntries = nKeepCnt;
+			c->m_iTotal = 0;
+
+			free(aKeep);
+		}	
+	}
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//											the function to generate texture confidence maps				                               //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, point*** aNeiDirArr, TextureModel**** aModel){
+	
+	int iBound_w = g_iRWidth-g_nRadius;
+	int iBound_h = g_iRHeight-g_nRadius;
+
+	short nNeighborNum = g_nNeighborNum;
+	float fPadding = 5;
+	
+	for(int h=0; h<g_iRHeight; h++){
+		for(int w=0;w<g_iRWidth;w++){
+
+			if(h<g_nRadius || h>=iBound_h || w<g_nRadius || w>=iBound_w){	
+				aTextureMap[h][w] = 0;
+				continue;
+			}
+
+			int nMatchedCount = 0;
+			float fDiffSum = 0;
+			float fDifference;
+			point nei;
+
+			for(int i=0;i<nNeighborNum;i++){
+
+				nei.m_nX = aNeiDirArr[h][w][i].m_nX;
+				nei.m_nY = aNeiDirArr[h][w][i].m_nY;
+
+				fDifference = (float)(aXYZ[h][w][2] - aXYZ[nei.m_nY][nei.m_nX][2]);
+				if(fDifference<0) fDiffSum -= fDifference;
+				else fDiffSum += fDifference;
+		
+				for(int j=0;j<aModel[h][w][i]->m_iNumEntries;j++){
+					if(aModel[h][w][i]->m_Codewords[j]->m_fLowThre-fPadding  <= fDifference && fDifference <= aModel[h][w][i]->m_Codewords[j]->m_fHighThre+fPadding){
+						nMatchedCount++;
+						break;
+					}
+				}
+
+			}
+			aTextureMap[h][w] = 1 - (float)nMatchedCount/nNeighborNum;
+		}
+	}
+}
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//											Absorbing Ghost Non-background Region Update					                               //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_Absorption(int iAbsorbCnt, point pos, short*** aContinuCnt, short*** aRefferedIndex, TextureModel** pModel, TextureModel** pCache){
+	int i,j,k;
+	int iLeavingIndex;
+
+	short g_nRadius = 2;
+	short nNeighborNum = g_nNeighborNum;
+
+	for(i=0;i<nNeighborNum;i++){
+		//set iLeavingIndex
+		if(aContinuCnt[pos.m_nY][pos.m_nX][i]<iAbsorbCnt) continue;
+
+		iLeavingIndex = aRefferedIndex[pos.m_nY][pos.m_nX][i];
+
+		//array expansion
+		if(pModel[i]->m_iElementArraySize==pModel[i]->m_iNumEntries){
+			pModel[i]->m_iElementArraySize = pModel[i]->m_iElementArraySize+5;
+			TextureCodeword** temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*pModel[i]->m_iElementArraySize);
+			for(j=0;j<pModel[i]->m_iNumEntries;j++) temp[j] = pModel[i]->m_Codewords[j];
+			free(pModel[i]->m_Codewords);
+			pModel[i]->m_Codewords = temp;
+		}
+
+		//movement from the cache-book to the codebook
+		pModel[i]->m_Codewords[pModel[i]->m_iNumEntries] = pCache[i]->m_Codewords[iLeavingIndex];
+
+		pModel[i]->m_iTotal = pModel[i]->m_iTotal+1;
+
+		pModel[i]->m_Codewords[pModel[i]->m_iNumEntries]->m_iT_first_time = pModel[i]->m_iTotal;
+		pModel[i]->m_Codewords[pModel[i]->m_iNumEntries]->m_iT_last_time = pModel[i]->m_iTotal;
+		pModel[i]->m_Codewords[pModel[i]->m_iNumEntries]->m_iMNRL = pModel[i]->m_iTotal-1;
+		pModel[i]->m_iNumEntries = pModel[i]->m_iNumEntries + 1;
+
+		k=0;
+		TextureCodeword **temp_Cache = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*pCache[i]->m_iElementArraySize);
+		for(j=0;j<pCache[i]->m_iNumEntries;j++){
+			if(j==iLeavingIndex) continue;
+			else{
+				temp_Cache[k] = pCache[i]->m_Codewords[j];
+				k++;
+			}
+		}
+		free(pCache[i]->m_Codewords);
+		pCache[i]->m_Codewords = temp_Cache;
+		pCache[i]->m_iNumEntries = k;
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//													the function to set neighborhood system												   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::T_SetNeighborDirection(point*** aNeighborPos){
+	int i,j,k;
+	point* aSearchDirection = (point*)malloc(sizeof(point)*g_nNeighborNum);
+
+	aSearchDirection[0].m_nX = -2;//180 degree
+	aSearchDirection[0].m_nY = 0;
+
+	aSearchDirection[1].m_nX = -1;//123 degree
+	aSearchDirection[1].m_nY = -2;
+
+	aSearchDirection[2].m_nX = 1;//45 degree
+	aSearchDirection[2].m_nY = -2;
+
+	aSearchDirection[3].m_nX = 2;//0 degree
+	aSearchDirection[3].m_nY = 0;
+
+	aSearchDirection[4].m_nX = 1;//-45 degree
+	aSearchDirection[4].m_nY = 2;
+
+	aSearchDirection[5].m_nX = -1;//-135 degree
+	aSearchDirection[5].m_nY = 2;
+
+	point temp_pos;
+
+	for(i=0;i<g_iRHeight;i++){
+		for(j=0;j<g_iRWidth;j++){
+			for(k=0;k<g_nNeighborNum;k++){
+				temp_pos.m_nX = j+aSearchDirection[k].m_nX;
+				temp_pos.m_nY = i+aSearchDirection[k].m_nY;
+
+				if(temp_pos.m_nX<0 || temp_pos.m_nX>=g_iRWidth || temp_pos.m_nY<0 || temp_pos.m_nY>=g_iRHeight) {
+					aNeighborPos[i][j][k].m_nX = -1;
+					aNeighborPos[i][j][k].m_nY = -1;
+				}
+
+				else {
+					aNeighborPos[i][j][k].m_nX = temp_pos.m_nX;
+					aNeighborPos[i][j][k].m_nY = temp_pos.m_nY;
+				}
+			}
+		}
+	}
+	free(aSearchDirection);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//													the color-model initialization function												   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::C_AllocateColorModelRelatedMemory(){
+	int i,j; 
+
+	int iElementArraySize = 10;
+	
+	//codebook initialization
+	g_ColorModel = (ColorModel***)malloc(sizeof(ColorModel**)*g_iRHeight);
+	for(i=0;i<g_iRHeight;i++){
+		g_ColorModel[i] = (ColorModel**)malloc(sizeof(ColorModel*)*g_iRWidth);
+		for(j=0;j<g_iRWidth;j++){
+			//initialization of each CodeBookArray.
+			g_ColorModel[i][j] = (ColorModel*)malloc(sizeof(ColorModel));
+			g_ColorModel[i][j]->m_Codewords = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*iElementArraySize);
+			g_ColorModel[i][j]->m_iNumEntries = 0;
+			g_ColorModel[i][j]->m_iElementArraySize = iElementArraySize;
+			g_ColorModel[i][j]->m_iTotal = 0;
+			g_ColorModel[i][j]->m_bID = 1;
+		}
+	}
+
+	//cache-book initialization
+	if(g_bAbsorptionEnable==TRUE){
+		iElementArraySize = 3;
+
+		g_CCacheBook = (ColorModel***)malloc(sizeof(ColorModel**)*g_iRHeight);
+		for(i=0;i<g_iRHeight;i++){
+			g_CCacheBook[i] = (ColorModel**)malloc(sizeof(ColorModel*)*g_iRWidth);
+			for(j=0;j<g_iRWidth;j++){
+				//initialization of each CodeBookArray.
+				g_CCacheBook[i][j] = (ColorModel*)malloc(sizeof(ColorModel));
+				g_CCacheBook[i][j]->m_Codewords = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*iElementArraySize);
+				g_CCacheBook[i][j]->m_iNumEntries = 0;
+				g_CCacheBook[i][j]->m_iElementArraySize = iElementArraySize;
+				g_CCacheBook[i][j]->m_iTotal = 0;
+				g_CCacheBook[i][j]->m_bID = 0;
+			}
+		}
+
+		g_aCReferredIndex = (short**)malloc(sizeof(short*)*g_iRHeight);
+		g_aCContinuousCnt = (short**)malloc(sizeof(short*)*g_iRHeight);
+		for(i=0;i<g_iRHeight;i++){
+			g_aCReferredIndex[i] = (short*)malloc(sizeof(short)*g_iRWidth);
+			g_aCContinuousCnt[i] = (short*)malloc(sizeof(short)*g_iRWidth);
+			for(j=0;j<g_iRWidth;j++){
+				g_aCReferredIndex[i][j] = -1;
+				g_aCContinuousCnt[i][j] = 0;
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//															the memory release function											           //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::C_ReleaseColorModelRelatedMemory(){
+	int i,j,k;
+
+	for(i=0;i<g_iRHeight;i++){           
+		for(j=0;j<g_iRWidth;j++){
+			for(k=0;k<g_ColorModel[i][j]->m_iNumEntries;k++){
+				free(g_ColorModel[i][j]->m_Codewords[k]);
+			}
+			free(g_ColorModel[i][j]->m_Codewords);
+			free(g_ColorModel[i][j]);
+		}
+		free(g_ColorModel[i]);
+	}
+	free(g_ColorModel);
+
+	if(g_bAbsorptionEnable==TRUE){
+		for(i=0;i<g_iRHeight;i++){           
+			for(j=0;j<g_iRWidth;j++){
+				for(k=0;k<g_CCacheBook[i][j]->m_iNumEntries;k++){
+					free(g_CCacheBook[i][j]->m_Codewords[k]);
+				}
+				free(g_CCacheBook[i][j]->m_Codewords);
+				free(g_CCacheBook[i][j]);
+			}
+			free(g_CCacheBook[i]);
+		}
+		free(g_CCacheBook);
+
+		for(i=0;i<g_iRHeight;i++){
+			free(g_aCReferredIndex[i]);
+			free(g_aCContinuousCnt[i]);
+		}
+		free(g_aCReferredIndex);
+		free(g_aCContinuousCnt);
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the codebook construction function								                   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP,int iPosX, int iPosY, short nTrainVolRange, float fLearningRate, ColorModel* pC){
+	
+	//Step1: matching
+	int i,j;
+	short nMatchedIndex;
+
+	float fNegLearningRate = 1-fLearningRate;
+
+	nMatchedIndex = -1;
+
+	for(i=0;i<pC->m_iNumEntries;i++){
+		
+		//Checking X
+		if(pC->m_Codewords[i]->m_dMean[0]-nTrainVolRange <= aP[0] && aP[0] <= pC->m_Codewords[i]->m_dMean[0]+nTrainVolRange){
+			//Checking Y
+			if(pC->m_Codewords[i]->m_dMean[1]-nTrainVolRange <= aP[1] && aP[1] <= pC->m_Codewords[i]->m_dMean[1]+nTrainVolRange){
+				//Checking Z
+				if(pC->m_Codewords[i]->m_dMean[2]-nTrainVolRange <= aP[2] && aP[2] <= pC->m_Codewords[i]->m_dMean[2]+nTrainVolRange){
+					nMatchedIndex = i;
+					break;
+				}
+			}
+		}
+	}
+
+	pC->m_iTotal = pC->m_iTotal+1;
+
+	//Step2 : adding a new element
+	if(nMatchedIndex==-1){
+		if(pC->m_iElementArraySize == pC->m_iNumEntries){
+			pC->m_iElementArraySize = pC->m_iElementArraySize + 5;
+			ColorCodeword **temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pC->m_iElementArraySize);
+			for(j=0;j<pC->m_iNumEntries;j++){
+				temp[j] = pC->m_Codewords[j];
+				pC->m_Codewords[j]= NULL;
+			}
+			free(pC->m_Codewords);
+			pC->m_Codewords = temp;
+
+		}
+		pC->m_Codewords[pC->m_iNumEntries] = (ColorCodeword*)malloc(sizeof(ColorCodeword));
+
+		pC->m_Codewords[pC->m_iNumEntries]->m_dMean[0] = aP[0];//X
+		pC->m_Codewords[pC->m_iNumEntries]->m_dMean[1] = aP[1];//Y
+		pC->m_Codewords[pC->m_iNumEntries]->m_dMean[2] = aP[2];//Z
+
+		pC->m_Codewords[pC->m_iNumEntries]->m_iT_first_time = pC->m_iTotal;
+		pC->m_Codewords[pC->m_iNumEntries]->m_iT_last_time = pC->m_iTotal;
+		pC->m_Codewords[pC->m_iNumEntries]->m_iMNRL = pC->m_iTotal-1;
+		pC->m_iNumEntries = pC->m_iNumEntries + 1;
+	}
+
+	//Step3 : update
+	else{		
+		//m_dMean update
+		pC->m_Codewords[nMatchedIndex]->m_dMean[0] = (fLearningRate*aP[0]) + fNegLearningRate*pC->m_Codewords[nMatchedIndex]->m_dMean[0];//X
+		pC->m_Codewords[nMatchedIndex]->m_dMean[1] = (fLearningRate*aP[1]) + fNegLearningRate*pC->m_Codewords[nMatchedIndex]->m_dMean[1];//Y
+		pC->m_Codewords[nMatchedIndex]->m_dMean[2] = (fLearningRate*aP[2]) + fNegLearningRate*pC->m_Codewords[nMatchedIndex]->m_dMean[2];//Z
+
+		pC->m_Codewords[nMatchedIndex]->m_iT_last_time = pC->m_iTotal;	
+	}
+
+	//cache-book handling
+	if(pC->m_bID==1){
+		//1. m_iMNRL update
+		int iNegTime;
+		for(i=0;i<pC->m_iNumEntries;i++){
+			//m_iMNRL update
+			iNegTime = pC->m_iTotal - pC->m_Codewords[i]->m_iT_last_time + pC->m_Codewords[i]->m_iT_first_time - 1;
+			if(pC->m_Codewords[i]->m_iMNRL < iNegTime) pC->m_Codewords[i]->m_iMNRL = iNegTime;
+		}
+
+		//2. g_aCReferredIndex[iPosY][iPosX] update
+		if(g_bAbsorptionEnable == TRUE) g_aCReferredIndex[iPosY][iPosX] = -1;
+	}
+	
+	else{
+		//1. m_iMNRL update:
+		if(nMatchedIndex == -1) pC->m_Codewords[pC->m_iNumEntries-1]->m_iMNRL = 0;
+		
+		//2. g_aCReferredIndex[iPosY][iPosX] update
+		if(nMatchedIndex==-1){
+			g_aCReferredIndex[iPosY][iPosX] = pC->m_iNumEntries-1;
+			g_aCContinuousCnt[iPosY][iPosX] = 1;
+		}
+		else{
+			if(nMatchedIndex == g_aCReferredIndex[iPosY][iPosX]) g_aCContinuousCnt[iPosY][iPosX]++;
+			else{
+				g_aCReferredIndex[iPosY][iPosX] = nMatchedIndex;
+				g_aCContinuousCnt[iPosY][iPosX] = 1;
+			}
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//												Clear non-essential codewords of the given codebook							               //																													   //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel){
+	int i;
+	short nStaleThresh = (int)(nClearNum*0.5);
+	short nKeepCnt;
+	int* aKeep;
+
+	ColorModel* pC = pModel;
+
+	if(pC->m_iTotal < nClearNum) return; //(Being operated only when pC->t >= nClearNum)
+
+	//Step1:initialization
+	aKeep = (int*)malloc(sizeof(int)*pC->m_iNumEntries);
+
+	nKeepCnt = 0;
+
+	//Step2: Find non-essential codewords
+	for(i=0;i<pC->m_iNumEntries;i++){
+		if(pC->m_Codewords[i]->m_iMNRL > nStaleThresh) {
+			aKeep[i] = 0; //removal
+		}
+		else {
+			aKeep[i] = 1; //keep
+			nKeepCnt++;
+		}
+	}
+
+	//Step3: Perform removal
+	if(nKeepCnt==0 || nKeepCnt==pC->m_iNumEntries){
+		for(i=0;i<pC->m_iNumEntries;i++){
+			pC->m_Codewords[i]->m_iT_first_time = 1;
+			pC->m_Codewords[i]->m_iT_last_time = 1;
+			pC->m_Codewords[i]->m_iMNRL = 0;
+		}
+	}
+	else{
+		nKeepCnt = 0;
+		ColorCodeword** temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pC->m_iNumEntries);
+
+		for(i=0;i<pC->m_iNumEntries;i++){
+			if(aKeep[i] == 1){
+				temp[nKeepCnt] = pC->m_Codewords[i];
+				temp[nKeepCnt]->m_iT_first_time = 1;
+				temp[nKeepCnt]->m_iT_last_time = 1;
+				temp[nKeepCnt]->m_iMNRL = 0;
+				nKeepCnt++;
+			}
+			else free(pC->m_Codewords[i]);
+		}
+
+		//ending..
+		free(pC->m_Codewords);
+		pC->m_Codewords = temp;
+		pC->m_iElementArraySize = pC->m_iNumEntries;
+		pC->m_iNumEntries = nKeepCnt;
+	}
+
+	pC->m_iTotal=0;
+	free(aKeep);
+
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//										Clear non-essential codewords of the given codebook (for cache-book)				               //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook){
+	int i;
+
+	if(pCachebook->m_iTotal<nClearNum) {
+		for(i=0;i<pCachebook->m_iNumEntries;i++){
+			if(bLandmark == 255 && i == nReferredIdx) pCachebook->m_Codewords[i]->m_iMNRL = 0;
+			else pCachebook->m_Codewords[i]->m_iMNRL++;
+		}
+
+		pCachebook->m_iTotal++;
+	}
+
+	else{
+		int iStaleThreshold = 5;
+
+		int* aKeep;
+		short nKeepCnt;
+
+		aKeep = (int*)malloc(sizeof(int)*pCachebook->m_iNumEntries);
+		nKeepCnt = 0;
+
+		for(i=0;i<pCachebook->m_iNumEntries;i++){
+			if(pCachebook->m_Codewords[i]->m_iMNRL<iStaleThreshold){
+				aKeep[i] = 1;
+				nKeepCnt++;
+			}
+			else aKeep[i] = 0;
+		}
+
+		pCachebook->m_iElementArraySize = nKeepCnt+2;
+		if(pCachebook->m_iElementArraySize<3) pCachebook->m_iElementArraySize = 3;
+
+		ColorCodeword** temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pCachebook->m_iElementArraySize);
+		nKeepCnt = 0;
+
+		for(i=0;i<pCachebook->m_iNumEntries;i++){
+			if(aKeep[i]==1){			
+				temp[nKeepCnt] = pCachebook->m_Codewords[i];
+				temp[nKeepCnt]->m_iMNRL = 0;
+				nKeepCnt++;
+			}
+			else {	
+				free(pCachebook->m_Codewords[i]);
+			}
+
+		}
+
+		//ending..
+		free(pCachebook->m_Codewords);
+		pCachebook->m_Codewords = temp;
+		pCachebook->m_iNumEntries = nKeepCnt;
+		pCachebook->m_iTotal = 0;
+
+		free(aKeep);
+	}
+}
+
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+//														the ghost-region absorption function										       //
+//-----------------------------------------------------------------------------------------------------------------------------------------//
+void SJN_MultiCueBGS::C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache){
+
+	//set iLeavingIndex
+	if(aContinuCnt[pos.m_nY][pos.m_nX]<iAbsorbCnt) return;
+
+	int iLeavingIndex = aRefferedIndex[pos.m_nY][pos.m_nX];
+
+	//array expansion
+	if(pModel->m_iElementArraySize==pModel->m_iNumEntries){
+		pModel->m_iElementArraySize = pModel->m_iElementArraySize+5;
+		ColorCodeword** temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pModel->m_iElementArraySize);
+		for(int i=0;i<pModel->m_iNumEntries;i++) temp[i] = pModel->m_Codewords[i];
+		free(pModel->m_Codewords);
+		pModel->m_Codewords = temp;
+	}
+
+	//movement from the cache-book to the codebook
+	pModel->m_Codewords[pModel->m_iNumEntries] = pCache->m_Codewords[iLeavingIndex];
+
+	pModel->m_iTotal = pModel->m_iTotal+1;
+
+	pModel->m_Codewords[pModel->m_iNumEntries]->m_iT_first_time = pModel->m_iTotal;
+	pModel->m_Codewords[pModel->m_iNumEntries]->m_iT_last_time = pModel->m_iTotal;
+	pModel->m_Codewords[pModel->m_iNumEntries]->m_iMNRL = pModel->m_iTotal-1;
+
+	pModel->m_iNumEntries = pModel->m_iNumEntries + 1;
+
+	int k=0;
+	ColorCodeword **pTempCache = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pCache->m_iElementArraySize);
+	for(int i=0;i<pCache->m_iNumEntries;i++){
+		if(i==iLeavingIndex) continue;
+		else{
+			pTempCache[k] = pCache->m_Codewords[i];
+			k++;
+		}
+	}
+	free(pCache->m_Codewords);
+	pCache->m_Codewords = pTempCache;
+	pCache->m_iNumEntries = k;
+}
\ No newline at end of file
diff --git a/package_bgs/sjn/SJN_MultiCueBGS.h b/package_bgs/sjn/SJN_MultiCueBGS.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d5dd7321c8d234ac7748e6991b8e86ae729e639
--- /dev/null
+++ b/package_bgs/sjn/SJN_MultiCueBGS.h
@@ -0,0 +1,243 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#define MIN3(x,y,z)  ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z)))
+#define MAX3(x,y,z)  ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z)))
+#define PI 3.14159
+
+typedef int BOOL;
+
+#ifndef FALSE
+  #define FALSE 0
+#endif
+
+#ifndef TRUE
+  #define TRUE 1
+#endif
+
+#include <malloc.h>
+#include "math.h"
+
+#include <vector>
+using std::vector;
+
+#include <algorithm>
+using std::sort;
+
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+
+//------------------------------------Structure Lists-------------------------------------//
+struct point{
+	short m_nX;
+	short m_nY;
+};
+
+struct neighbor_pos{
+	short m_nX;
+	short m_nY;
+};
+//1) Bounding Box Structure
+struct BoundingBoxInfo{
+	int m_iBoundBoxNum;										//# of bounding boxes for all foreground and false-positive blobs
+	int m_iArraySize;										//the size of the below arrays to store bounding box information
+
+	short *m_aLeft, *m_aRight, *m_aUpper, *m_aBottom;		//arrays to store bounding box information for (the original frame size)
+	short *m_aRLeft, *m_aRRight, *m_aRUpper, *m_aRBottom;	//arrays to store bounding box information for (the reduced frame size)
+	BOOL* m_ValidBox;										//If this value is true, the corresponding bounding box is for a foreground blob.
+															//Else, it is for a false-positive blob
+};
+
+//2) Texture Model Structure
+struct TextureCodeword{
+	int m_iMNRL;											//the maximum negative run-length
+	int m_iT_first_time;									//the first access time
+	int m_iT_last_time;										//the last access time
+
+	//��� MTLBP��
+	float m_fLowThre;										//a low threshold for the matching 
+	float m_fHighThre;										//a high threshold for the matching
+	float m_fMean;											//mean of the codeword
+};
+
+struct TextureModel{
+	TextureCodeword** m_Codewords;							//the texture-codeword Array
+
+	int m_iTotal;											//# of learned samples after the last clear process
+	int m_iElementArraySize;								//the array size of m_Codewords
+	int m_iNumEntries;										//# of codewords
+
+	BOOL m_bID;												//id=1 --> background model, id=0 --> cachebook
+};
+
+//3) Color Model Structure
+struct ColorCodeword{	
+	int m_iMNRL;											//the maximum negative run-length
+	int m_iT_first_time;									//the first access time
+	int m_iT_last_time;										//the last access time
+
+	double m_dMean[3];										//mean vector of the codeword
+
+};
+
+struct ColorModel{
+	ColorCodeword** m_Codewords;							//the color-codeword Array
+
+	int m_iTotal;											//# of learned samples after the last clear process
+	int m_iElementArraySize;								//the array size of m_Codewords
+	int m_iNumEntries;										//# of codewords
+
+	BOOL m_bID;												//id=1 --> background model, id=0 --> cachebookk
+};
+
+
+class SJN_MultiCueBGS : public IBGS
+{
+private:
+  bool firstTime;
+  bool showOutput;
+  void saveConfig();
+  void loadConfig();
+
+public:
+	SJN_MultiCueBGS();
+	~SJN_MultiCueBGS(void);
+
+public:
+	//----------------------------------------------------
+	//		APIs and User-Adjustable Parameters
+	//----------------------------------------------------
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);			//the main function to background modeling and subtraction
+  
+  void GetForegroundMap(IplImage* return_image, IplImage* input_frame=NULL);					//the function returning a foreground binary-map
+	void Destroy();																				//the function to release allocated memories
+
+	int g_iTrainingPeriod;										//the training period								(The parameter t in the paper)
+	int g_iT_ModelThreshold;									//the threshold for texture-model based BGS.		(The parameter tau_T in the paper)
+	int g_iC_ModelThreshold;									//the threshold for appearance based verification.  (The parameter tau_A in the paper)
+
+	float g_fLearningRate;										//the learning rate for background models.			(The parameter alpha in the paper)
+
+	short g_nTextureTrainVolRange;								//the codebook size factor for texture models.		(The parameter k in the paper)
+	short g_nColorTrainVolRange;								//the codebook size factor for color models.		(The parameter eta_1 in the paper)
+
+public:
+	//----------------------------------------------------
+	//	Implemented Function Lists
+	//----------------------------------------------------
+
+	//--1) General Functions
+	void Initialize(IplImage* frame);
+
+	void PreProcessing(IplImage* frame);
+	void ReduceImageSize(IplImage* SrcImage, IplImage* DstImage);
+	void GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame);
+	void BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ);
+
+	void BackgroundModeling_Par(IplImage* frame);
+	void ForegroundExtraction(IplImage* frame);
+	void CreateLandmarkArray_Par(float fConfThre, short nTrainVolRange, float**aConfMap, int iNehborNum, uchar*** aXYZ, 
+		point*** aNeiDir, TextureModel**** TModel, ColorModel*** CModel, uchar**aLandmarkArr);
+
+	void PostProcessing(IplImage* frame);
+	void MorphologicalOpearions(uchar** aInput, uchar** aOutput, double dThresholdRatio, int iMaskSize, int iWidth, int iHeight);
+	void Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLabelTable);
+	void SetBoundingBox(int iLabelCount, int** aLabelTable);
+	void BoundBoxVerification(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo);
+	void EvaluateBoxSize( BoundingBoxInfo* BoundBoxInfo);
+	void EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo);
+	void EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo);
+	double CalculateHausdorffDist(IplImage* input_image, IplImage* model_image);
+	void RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo);
+	
+	void UpdateModel_Par();
+	void GetEnlargedMap(float** aOriginMap, float** aEnlargedMap);
+
+	//--2) Texture Model Related Functions
+	void T_AllocateTextureModelRelatedMemory();
+	void T_ReleaseTextureModelRelatedMemory();
+	void T_SetNeighborDirection(point*** aNeighborPos);
+	void T_ModelConstruction(short nTrainVolRange,float fLearningRate, uchar*** aXYZ,point center, point* aNei, TextureModel** aModel);
+	void T_ClearNonEssentialEntries(short nClearNum, TextureModel** aModel);
+	void T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short* nReferredIdxArr, short nClearNum, TextureModel** pCachebook);
+	void T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, point*** aNeiDirArr, TextureModel**** aModel);
+	void T_Absorption(int iAbsorbCnt, point pos, short*** aContinuCnt, short*** aRefferedIndex, TextureModel** pModel, TextureModel** pCache);
+
+	//--3) Color Model Related Functions
+	void C_AllocateColorModelRelatedMemory();
+	void C_ReleaseColorModelRelatedMemory();
+	void C_CodebookConstruction(uchar* aP,int iPosX, int iPosY, short nTrainVolRange, float fLearningRate, ColorModel* pC);
+	void C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel);
+	void C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook);
+	void C_Absorption(int iAbsorbCnt, point pos , short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache);
+public: 
+	//----------------------------------------------------
+	//	Implemented Variable Lists
+	//----------------------------------------------------
+	
+	//--1) General Variables
+	int g_iFrameCount;							//the counter of processed frames
+
+	int g_iBackClearPeriod;						//the period to clear background models
+	int g_iCacheClearPeriod;					//the period to clear cache-book models
+
+	int g_iAbsortionPeriod;						//the period to absorb static ghost regions 
+	BOOL g_bAbsorptionEnable;					//If True, procedures for ghost region absorption are activated.
+
+	BOOL g_bModelMemAllocated;					//To handle memory..
+	BOOL g_bNonModelMemAllocated;				//To handle memory..
+
+	float g_fConfidenceThre;					//the final decision threshold
+
+	int g_iWidth, g_iHeight;					//width and height of input frames
+	int g_iRWidth, g_iRHeight;					//width and height of reduced frames (For efficiency, the reduced size of frames are processed) 
+	int g_iForegroundNum;						//# of detected foreground regions
+	BOOL g_bForegroundMapEnable;				//TRUE only when BGS is successful
+
+	IplImage* g_ResizedFrame;					//reduced size of frame (For efficiency, the reduced size of frames are processed) 
+	uchar*** g_aGaussFilteredFrame;				
+	uchar*** g_aXYZFrame;						
+	uchar** g_aLandmarkArray;					//the landmark map
+	uchar** g_aResizedForeMap;					//the resized foreground map
+	uchar** g_aForegroundMap;					//the final foreground map
+	BOOL** g_aUpdateMap;						//the location map of update candidate pixels
+
+	BoundingBoxInfo* g_BoundBoxInfo;			//the array of bounding boxes of each foreground blob
+
+	//--2) Texture Model Related
+	TextureModel**** g_TextureModel;			//the texture background model
+	TextureModel**** g_TCacheBook;				//the texture cache-book
+	short*** g_aTReferredIndex;					//To handle cache-book
+	short*** g_aTContinuousCnt;					//To handle cache-book
+	point*** g_aNeighborDirection;				
+	float**g_aTextureConfMap;					//the texture confidence map
+
+	short g_nNeighborNum;						//# of neighborhoods
+	short g_nRadius;							
+	short g_nBoundarySize;						
+	
+	//--3) Texture Model Related
+	ColorModel*** g_ColorModel;					//the color background model
+	ColorModel*** g_CCacheBook;					//the color cache-book
+	short** g_aCReferredIndex;					//To handle cache-book
+	short** g_aCContinuousCnt;					//To handle cache-book
+};
+
+
diff --git a/package_bgs/tb/FuzzyChoquetIntegral.cpp b/package_bgs/tb/FuzzyChoquetIntegral.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7d0bf908041a308543aff7c7510466bcb84a09bd
--- /dev/null
+++ b/package_bgs/tb/FuzzyChoquetIntegral.cpp
@@ -0,0 +1,204 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "FuzzyChoquetIntegral.h"
+
+FuzzyChoquetIntegral::FuzzyChoquetIntegral() : firstTime(true), frameNumber(0), showOutput(true),
+  framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), colorSpace(1), option(2), smooth(true), threshold(0.67)
+{
+  std::cout << "FuzzyChoquetIntegral()" << std::endl;
+}
+
+FuzzyChoquetIntegral::~FuzzyChoquetIntegral()
+{
+  std::cout << "~FuzzyChoquetIntegral()" << std::endl;
+}
+
+void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  cv::Mat img_input_f3(img_input.size(), CV_32F);
+  img_input.convertTo(img_input_f3, CV_32F, 1./255.);
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    std::cout << "FuzzyChoquetIntegral parameters:" << std::endl;
+      
+    std::string colorSpaceName = "";
+    switch(colorSpace)
+    {
+      case 1: colorSpaceName = "RGB";  break;
+      case 2: colorSpaceName = "OHTA"; break;
+      case 3: colorSpaceName = "HSV";  break;
+      case 4: colorSpaceName = "YCrCb"; break;
+    }
+    std::cout << "Color space: " << colorSpaceName << std::endl;
+
+    if(option == 1)
+      std::cout << "Fuzzing by 3 color components" << std::endl;
+    if(option == 2)
+      std::cout << "Fuzzing by 2 color components + 1 texture component" << std::endl;
+    
+    saveConfig();
+  }
+
+  if(frameNumber <= framesToLearn)
+  {
+    if(frameNumber == 0)
+      std::cout << "FuzzyChoquetIntegral initializing background model by adaptive learning..." << std::endl;
+
+    if(img_background_f3.empty())
+      img_input_f3.copyTo(img_background_f3);
+    else
+      img_background_f3 = alphaLearn*img_input_f3 + (1-alphaLearn)*img_background_f3;
+
+    if(showOutput)
+      cv::imshow("CI BG Model", img_background_f3);
+  }
+  else
+  {
+    cv::Mat img_input_f1;
+    cv::cvtColor(img_input_f3, img_input_f1, CV_BGR2GRAY);
+
+    cv::Mat img_background_f1;
+    cv::cvtColor(img_background_f3, img_background_f1, CV_BGR2GRAY);
+
+    IplImage* input_f3 = new IplImage(img_input_f3);
+    IplImage* input_f1 = new IplImage(img_input_f1);
+    IplImage* background_f3 = new IplImage(img_background_f3);
+    IplImage* background_f1 = new IplImage(img_background_f1);
+
+    IplImage* lbp_input_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1);
+    cvFillImage(lbp_input_f1, 0.0);
+    fu.LBP(input_f1, lbp_input_f1);
+
+    IplImage* lbp_background_f1 = cvCreateImage(cvSize(background_f1->width, background_f1->height), IPL_DEPTH_32F , 1);
+    cvFillImage(lbp_background_f1, 0.0);
+    fu.LBP(background_f1, lbp_background_f1);
+
+    IplImage* sim_texture_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1);
+    fu.SimilarityDegreesImage(lbp_input_f1, lbp_background_f1, sim_texture_f1, 1, colorSpace);
+
+    IplImage* sim_color_f3 = cvCreateImage(cvSize(input_f3->width, input_f3->height), IPL_DEPTH_32F, 3);
+    fu.SimilarityDegreesImage(input_f3, background_f3, sim_color_f3, 3, colorSpace);	
+
+    float* measureG = (float*) malloc(3*(sizeof(float)));
+    IplImage* integral_choquet_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1);
+
+    // 3 color components
+    if(option == 1)
+    {
+      fu.FuzzyMeasureG(0.4, 0.3, 0.3, measureG);
+      fu.getFuzzyIntegralChoquet(sim_texture_f1, sim_color_f3, option, measureG, integral_choquet_f1);
+    }
+
+    // 2 color components + 1 texture component
+    if(option == 2)
+    {
+      fu.FuzzyMeasureG(0.6, 0.3, 0.1, measureG);
+      fu.getFuzzyIntegralChoquet(sim_texture_f1, sim_color_f3, option, measureG, integral_choquet_f1);
+    }
+
+    free(measureG);
+    cv::Mat img_integral_choquet_f1(integral_choquet_f1);
+
+    if(smooth)
+      cv::medianBlur(img_integral_choquet_f1, img_integral_choquet_f1, 3);
+
+    cv::Mat img_foreground_f1(img_input.size(), CV_32F);
+    cv::threshold(img_integral_choquet_f1, img_foreground_f1, threshold, 255, cv::THRESH_BINARY_INV);
+
+    cv::Mat img_foreground_u1(img_input.size(), CV_8U);
+    double minVal = 0., maxVal = 1.;
+    img_foreground_f1.convertTo(img_foreground_u1, CV_8U, 255.0/(maxVal - minVal), -minVal);
+    img_foreground_u1.copyTo(img_output);
+
+    cv::Mat img_background_u3(img_input.size(), CV_8U);
+    //double minVal = 0., maxVal = 1.;
+    img_background_f3.convertTo(img_background_u3, CV_8U, 255.0/(maxVal - minVal), -minVal);
+    img_background_u3.copyTo(img_bgmodel);
+
+    if(showOutput)
+    {
+      cvShowImage("CI LBP Input", lbp_input_f1);
+      cvShowImage("CI LBP Background", lbp_background_f1);
+      cvShowImage("CI Prob FG Mask", integral_choquet_f1);
+
+      cv::imshow("CI BG Model", img_background_f3);
+      cv::imshow("CI FG Mask", img_foreground_u1);
+    }
+
+    if(frameNumber == (framesToLearn + 1))
+      std::cout << "FuzzyChoquetIntegral updating background model by adaptive-selective learning..." << std::endl;
+
+    IplImage* updated_background_f3 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 3);
+    cvFillImage(updated_background_f3, 0.0);
+    fu.AdaptativeSelectiveBackgroundModelUpdate(input_f3, background_f3, updated_background_f3, integral_choquet_f1, threshold, alphaUpdate);
+    cv::Mat img_updated_background_f3(updated_background_f3);
+    img_updated_background_f3.copyTo(img_background_f3);
+
+    cvReleaseImage(&lbp_input_f1);
+    cvReleaseImage(&lbp_background_f1);
+    cvReleaseImage(&sim_texture_f1);
+    cvReleaseImage(&sim_color_f3);
+    cvReleaseImage(&integral_choquet_f1);
+    cvReleaseImage(&updated_background_f3);
+    
+    delete background_f1;
+    delete background_f3;
+    delete input_f1;
+    delete input_f3;
+  }
+
+  firstTime = false;
+  frameNumber++;
+}
+
+void FuzzyChoquetIntegral::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FuzzyChoquetIntegral.xml", 0, CV_STORAGE_WRITE);
+  
+  cvWriteInt(fs, "showOutput", showOutput);
+  cvWriteInt(fs, "framesToLearn", framesToLearn);
+  cvWriteReal(fs, "alphaLearn", alphaLearn);
+  cvWriteReal(fs, "alphaUpdate", alphaUpdate);
+  cvWriteInt(fs, "colorSpace", colorSpace);
+  cvWriteInt(fs, "option", option);
+  cvWriteInt(fs, "smooth", smooth);
+  cvWriteReal(fs, "threshold", threshold);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void FuzzyChoquetIntegral::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FuzzyChoquetIntegral.xml", 0, CV_STORAGE_READ);
+  
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+  framesToLearn = cvReadIntByName(fs, 0, "framesToLearn", 10);
+  alphaLearn = cvReadRealByName(fs, 0, "alphaLearn", 0.1);
+  alphaUpdate = cvReadRealByName(fs, 0, "alphaUpdate", 0.01);
+  colorSpace = cvReadIntByName(fs, 0, "colorSpace", 1);
+  option = cvReadIntByName(fs, 0, "option", 2);
+  smooth = cvReadIntByName(fs, 0, "smooth", true);
+  threshold = cvReadRealByName(fs, 0, "threshold", 0.67);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/tb/FuzzyChoquetIntegral.h b/package_bgs/tb/FuzzyChoquetIntegral.h
new file mode 100644
index 0000000000000000000000000000000000000000..a52a52d804aea91b9873994f3e59bcec02652a40
--- /dev/null
+++ b/package_bgs/tb/FuzzyChoquetIntegral.h
@@ -0,0 +1,55 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+
+#include "FuzzyUtils.h"
+
+class FuzzyChoquetIntegral : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  bool showOutput;
+  
+  int framesToLearn;
+  double alphaLearn;
+  double alphaUpdate;
+  int colorSpace;
+  int option;
+  bool smooth;
+  double threshold;
+
+  FuzzyUtils fu;
+  cv::Mat img_background_f3;
+
+public:
+  FuzzyChoquetIntegral();
+  ~FuzzyChoquetIntegral();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/tb/FuzzySugenoIntegral.cpp b/package_bgs/tb/FuzzySugenoIntegral.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..34b1c027ddd3a578afa13bd230deb2b448c014d1
--- /dev/null
+++ b/package_bgs/tb/FuzzySugenoIntegral.cpp
@@ -0,0 +1,204 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "FuzzySugenoIntegral.h"
+
+FuzzySugenoIntegral::FuzzySugenoIntegral() : firstTime(true), frameNumber(0), showOutput(true),
+  framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), colorSpace(1), option(2), smooth(true), threshold(0.67)
+{
+  std::cout << "FuzzySugenoIntegral()" << std::endl;
+}
+
+FuzzySugenoIntegral::~FuzzySugenoIntegral()
+{
+  std::cout << "~FuzzySugenoIntegral()" << std::endl;
+}
+
+void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  cv::Mat img_input_f3(img_input.size(), CV_32F);
+  img_input.convertTo(img_input_f3, CV_32F, 1./255.);
+
+  loadConfig();
+
+  if(firstTime)
+  {
+    std::cout << "FuzzySugenoIntegral parameters:" << std::endl;
+      
+    std::string colorSpaceName = "";
+    switch(colorSpace)
+    {
+      case 1: colorSpaceName = "RGB";  break;
+      case 2: colorSpaceName = "OHTA"; break;
+      case 3: colorSpaceName = "HSV";  break;
+      case 4: colorSpaceName = "YCrCb"; break;
+    }
+    std::cout << "Color space: " << colorSpaceName << std::endl;
+
+    if(option == 1)
+      std::cout << "Fuzzing by 3 color components" << std::endl;
+    if(option == 2)
+      std::cout << "Fuzzing by 2 color components + 1 texture component" << std::endl;
+    
+    saveConfig();
+  }
+
+  if(frameNumber <= framesToLearn)
+  {
+    if(frameNumber == 0)
+      std::cout << "FuzzySugenoIntegral initializing background model by adaptive learning..." << std::endl;
+
+    if(img_background_f3.empty())
+      img_input_f3.copyTo(img_background_f3);
+    else
+      img_background_f3 = alphaLearn*img_input_f3 + (1-alphaLearn)*img_background_f3;
+
+    if(showOutput)
+      cv::imshow("SI BG Model", img_background_f3);
+  }
+  else
+  {
+    cv::Mat img_input_f1;
+    cv::cvtColor(img_input_f3, img_input_f1, CV_BGR2GRAY);
+
+    cv::Mat img_background_f1;
+    cv::cvtColor(img_background_f3, img_background_f1, CV_BGR2GRAY);
+
+    IplImage* input_f3 = new IplImage(img_input_f3);
+    IplImage* input_f1 = new IplImage(img_input_f1);
+    IplImage* background_f3 = new IplImage(img_background_f3);
+    IplImage* background_f1 = new IplImage(img_background_f1);
+
+    IplImage* lbp_input_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1);
+    cvFillImage(lbp_input_f1, 0.0);
+    fu.LBP(input_f1, lbp_input_f1);
+
+    IplImage* lbp_background_f1 = cvCreateImage(cvSize(background_f1->width, background_f1->height), IPL_DEPTH_32F , 1);
+    cvFillImage(lbp_background_f1, 0.0);
+    fu.LBP(background_f1, lbp_background_f1);
+
+    IplImage* sim_texture_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1);
+    fu.SimilarityDegreesImage(lbp_input_f1, lbp_background_f1, sim_texture_f1, 1, colorSpace);
+
+    IplImage* sim_color_f3 = cvCreateImage(cvSize(input_f3->width, input_f3->height), IPL_DEPTH_32F, 3);
+    fu.SimilarityDegreesImage(input_f3, background_f3, sim_color_f3, 3, colorSpace);	
+
+    float* measureG = (float*) malloc(3*(sizeof(float)));
+    IplImage* integral_sugeno_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1);
+
+    // 3 color components
+    if(option == 1)
+    {
+      fu.FuzzyMeasureG(0.4, 0.3, 0.3, measureG);
+      fu.getFuzzyIntegralSugeno(sim_texture_f1, sim_color_f3, option, measureG, integral_sugeno_f1);
+    }
+
+    // 2 color components + 1 texture component
+    if(option == 2)
+    {
+      fu.FuzzyMeasureG(0.6, 0.3, 0.1, measureG);
+      fu.getFuzzyIntegralSugeno(sim_texture_f1, sim_color_f3, option, measureG, integral_sugeno_f1);
+    }
+
+    free(measureG);
+    cv::Mat img_integral_sugeno_f1(integral_sugeno_f1);
+
+    if(smooth)
+      cv::medianBlur(img_integral_sugeno_f1, img_integral_sugeno_f1, 3);
+
+    cv::Mat img_foreground_f1(img_input.size(), CV_32F);
+    cv::threshold(img_integral_sugeno_f1, img_foreground_f1, threshold, 255, cv::THRESH_BINARY_INV);
+
+    cv::Mat img_foreground_u1(img_input.size(), CV_8U);
+    double minVal = 0., maxVal = 1.;
+    img_foreground_f1.convertTo(img_foreground_u1, CV_8U, 255.0/(maxVal - minVal), -minVal);
+    img_foreground_u1.copyTo(img_output);
+    
+    cv::Mat img_background_u3(img_input.size(), CV_8U);
+    //double minVal = 0., maxVal = 1.;
+    img_background_f3.convertTo(img_background_u3, CV_8U, 255.0/(maxVal - minVal), -minVal);
+    img_background_u3.copyTo(img_bgmodel);
+
+    if(showOutput)
+    {
+      cvShowImage("SI LBP Input", lbp_input_f1);
+      cvShowImage("SI LBP Background", lbp_background_f1);
+      cvShowImage("SI Prob FG Mask", integral_sugeno_f1);
+
+      cv::imshow("SI BG Model", img_background_f3);
+      cv::imshow("SI FG Mask", img_foreground_u1);
+    }
+
+    if(frameNumber == (framesToLearn + 1))
+      std::cout << "FuzzySugenoIntegral updating background model by adaptive-selective learning..." << std::endl;
+
+    IplImage* updated_background_f3 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 3);
+    cvFillImage(updated_background_f3, 0.0);
+    fu.AdaptativeSelectiveBackgroundModelUpdate(input_f3, background_f3, updated_background_f3, integral_sugeno_f1, threshold, alphaUpdate);
+    cv::Mat img_updated_background_f3(updated_background_f3);
+    img_updated_background_f3.copyTo(img_background_f3);
+
+    cvReleaseImage(&lbp_input_f1);
+    cvReleaseImage(&lbp_background_f1);
+    cvReleaseImage(&sim_texture_f1);
+    cvReleaseImage(&sim_color_f3);
+    cvReleaseImage(&integral_sugeno_f1);
+    cvReleaseImage(&updated_background_f3);
+    
+    delete background_f1;
+    delete background_f3;
+    delete input_f1;
+    delete input_f3;
+  }
+
+  firstTime = false;
+  frameNumber++;
+}
+
+void FuzzySugenoIntegral::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FuzzySugenoIntegral.xml", 0, CV_STORAGE_WRITE);
+  
+  cvWriteInt(fs, "showOutput", showOutput);
+  cvWriteInt(fs, "framesToLearn", framesToLearn);
+  cvWriteReal(fs, "alphaLearn", alphaLearn);
+  cvWriteReal(fs, "alphaUpdate", alphaUpdate);
+  cvWriteInt(fs, "colorSpace", colorSpace);
+  cvWriteInt(fs, "option", option);
+  cvWriteInt(fs, "smooth", smooth);
+  cvWriteReal(fs, "threshold", threshold);
+  
+  cvReleaseFileStorage(&fs);
+}
+
+void FuzzySugenoIntegral::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/FuzzySugenoIntegral.xml", 0, CV_STORAGE_READ);
+  
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+  framesToLearn = cvReadIntByName(fs, 0, "framesToLearn", 10);
+  alphaLearn = cvReadRealByName(fs, 0, "alphaLearn", 0.1);
+  alphaUpdate = cvReadRealByName(fs, 0, "alphaUpdate", 0.01);
+  colorSpace = cvReadIntByName(fs, 0, "colorSpace", 1);
+  option = cvReadIntByName(fs, 0, "option", 2);
+  smooth = cvReadIntByName(fs, 0, "smooth", true);
+  threshold = cvReadRealByName(fs, 0, "threshold", 0.67);
+  
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/tb/FuzzySugenoIntegral.h b/package_bgs/tb/FuzzySugenoIntegral.h
new file mode 100644
index 0000000000000000000000000000000000000000..11445596948f402d8ccea0ebd18f4f3cccc7590c
--- /dev/null
+++ b/package_bgs/tb/FuzzySugenoIntegral.h
@@ -0,0 +1,55 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+
+#include "FuzzyUtils.h"
+
+class FuzzySugenoIntegral : public IBGS
+{
+private:
+  bool firstTime;
+  long long frameNumber;
+  bool showOutput;
+  
+  int framesToLearn;
+  double alphaLearn;
+  double alphaUpdate;
+  int colorSpace;
+  int option;
+  bool smooth;
+  double threshold;
+
+  FuzzyUtils fu;
+  cv::Mat img_background_f3;
+  
+public:
+  FuzzySugenoIntegral();
+  ~FuzzySugenoIntegral();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/tb/FuzzyUtils.cpp b/package_bgs/tb/FuzzyUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..84d5a5092da97601ebe2608351362de7465e9206
--- /dev/null
+++ b/package_bgs/tb/FuzzyUtils.cpp
@@ -0,0 +1,511 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "FuzzyUtils.h"
+
+FuzzyUtils::FuzzyUtils(void){}
+
+FuzzyUtils::~FuzzyUtils(void){}
+
+void FuzzyUtils::LBP(IplImage* InputImage, IplImage* LBPimage)
+{
+  PixelUtils p;
+
+  float* neighberPixel = (float*) malloc(9*sizeof(float));   
+  float* BinaryValue = (float*) malloc(9*sizeof(float));
+  float* CarreExp = (float*) malloc(9*sizeof(float));
+  float* valLBP = (float*) malloc(1*sizeof(float));
+
+  *valLBP = 0;
+
+  int x = 0, y = 0;
+
+  // on implemente les 8 valeurs puissance de 2 qui correspondent aux 8 elem. d'image voisins au elem. d'image central
+  *(CarreExp+0)=1.0;
+  *(CarreExp+1)=2.0;
+  *(CarreExp+2)=4.0;
+  *(CarreExp+3)=8.0;
+  *(CarreExp+4)=0.0;
+  *(CarreExp+5)=16.0;
+  *(CarreExp+6)=32.0;
+  *(CarreExp+7)=64.0;
+  *(CarreExp+8)=128.0;
+
+  //le calcule de LBP
+  //pour les 4 coins
+  /* 1.*/
+  if(x==0 && y==0)
+  {
+    p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+    getBinValue(neighberPixel,BinaryValue,4,0);
+    *valLBP=*valLBP+((*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3)))/255.0;
+    p.PutGrayPixel(LBPimage,x,y,*valLBP);	
+  }
+
+  /* 2.*/
+  if(x==0 && y==InputImage->width)
+  {
+    *valLBP=0;
+    p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+    getBinValue(neighberPixel,BinaryValue,4,1);
+    *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3)))/255.0;
+    p.PutGrayPixel(LBPimage,x,y,*valLBP);	
+  }
+
+  /* 3.*/
+  if(x==InputImage->height && y==0)
+  {
+    *valLBP=0;
+    p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+    getBinValue(neighberPixel,BinaryValue,4,2);
+    *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+3))*(*(CarreExp+3)))/255.0;
+    p.PutGrayPixel(LBPimage,x,y,*valLBP);	
+  }
+
+  /* 4.*/
+  if(x==InputImage->height && y==InputImage->width)
+  {
+    *valLBP=0;
+    p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+    getBinValue(neighberPixel,BinaryValue,4,3);
+    *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2)))/255.0;
+    p.PutGrayPixel(LBPimage,x,y,*valLBP);	
+  }
+
+  //le calcul de LBP pour la premi�re ligne : L(0)
+  if(x==0 && (y!=0 && y!=InputImage->width))
+  {
+    for(int y = 1; y < InputImage->width-1; y++)
+    {
+      p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+      getBinValue(neighberPixel,BinaryValue,6,4);
+      *valLBP=0;
+      *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+5))*(*(CarreExp+5)))/255.0;
+      p.PutGrayPixel(LBPimage,x,y,*valLBP);
+    }
+  }
+
+  //le calcul de LBP pour la derni�re colonne : C(w)
+  if((x!=0 && x!=InputImage->height) && y==InputImage->width) 
+  {
+    for(int x = 1; x < InputImage->height-1; x++)
+    {
+      p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+      getBinValue(neighberPixel,BinaryValue,6,4);
+      *valLBP=0;
+      *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+5))*(*(CarreExp+5)))/255.0;
+      p.PutGrayPixel(LBPimage,x,y,*valLBP);
+    }
+  }
+
+  //le calcul de LBP pour la derni�re ligne : L(h)
+  if(x==InputImage->height && (y!=0 && y!=InputImage->width))
+  {
+    for(int y = 1; y < InputImage->width-1; y++)
+    {
+      p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+      getBinValue(neighberPixel,BinaryValue,6,1);
+      *valLBP=0;
+      *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+4))*(*(CarreExp+4))+(*(BinaryValue+5))*(*(CarreExp+5)))/255.0;
+      p.PutGrayPixel(LBPimage,x,y,*valLBP);
+    }
+  }
+
+  //le calcul de LBP pour la premi�re colonne : C(0)
+  if((x!=0 && x!=InputImage->height) && y==0)
+  {
+    for(int x = 1; x <InputImage->height-1; x++)
+    {
+      p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+      getBinValue(neighberPixel,BinaryValue,6,2);
+      *valLBP=0;
+      *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp+5))+(*(BinaryValue+1))*(*(CarreExp+6))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+4))*(*(CarreExp))+(*(BinaryValue+5))*(*(CarreExp+1)))/255.0;
+      p.PutGrayPixel(LBPimage,x,y,*valLBP);
+    }
+  }
+
+  //pour le reste des elements d'image
+  for(int y = 1; y < InputImage->height-1; y++)
+  {
+    for(int x = 1; x < InputImage->width-1; x++)
+    {
+      p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel);
+      getBinValue(neighberPixel,BinaryValue,9,4);
+      //le calcul de la valeur du LBP pour chaque elem. d'im.
+      *valLBP=0;
+      for(int l = 0; l < 9; l++)
+        *valLBP = *valLBP + ((*(BinaryValue+l)) * (*(CarreExp+l))) / 255.0;
+      //printf("\nvalLBP(%d,%d)=%f",x,y,*valLBP);
+      p.PutGrayPixel(LBPimage,x,y,*valLBP);	
+    }
+  }
+
+  free(neighberPixel);
+  free(BinaryValue);
+  free(CarreExp);
+  free(valLBP);
+}
+
+void FuzzyUtils::getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n)
+{
+  // la comparaison entre la valeur d'elem d'image central et les valeurs des elem. d'im. voisins
+  // m = le numero des elements (4, 6 ou 9);
+  // n = la position de l'element central; 
+
+  int h = 0;
+  for(int k = 0; k < m; k++)
+  {
+    if(*(neighberGrayPixel+k) >= *(neighberGrayPixel+n))
+    {
+      *(BinaryValue+h)=1;
+      h++;
+    }
+    else
+    {
+      *(BinaryValue+h)=0;
+      h++;
+    }	
+  }
+}
+
+void FuzzyUtils::SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space)
+{
+  PixelUtils p;
+  int i, j;
+
+  if(n == 1)
+  {
+    float* CurrentGrayPixel = (float*) malloc (1*(sizeof(float)));
+    float* BGGrayPixel = (float*) malloc (1*(sizeof(float)));
+    float* DeltaGrayPixel = (float*) malloc (1*(sizeof(float)));
+
+    for(i = 0; i < CurrentImage->width; i++)
+    {
+      for(j = 0; j < CurrentImage->height; j++)
+      {
+        p.GetGrayPixel(CurrentImage,i,j,CurrentGrayPixel);
+        p.GetGrayPixel(BGImage,i,j,BGGrayPixel);
+        RatioPixels(CurrentGrayPixel,BGGrayPixel,DeltaGrayPixel,1);
+        p.PutGrayPixel(DeltaImage,i,j,*DeltaGrayPixel);
+      }
+    }
+
+    free(CurrentGrayPixel);
+    free(BGGrayPixel);
+    free(DeltaGrayPixel);
+  }
+
+  if(n != 1)
+  {   
+    IplImage* ConvertedCurrentImage = cvCreateImage(cvSize(CurrentImage->width, CurrentImage->height), IPL_DEPTH_32F, 3);
+    IplImage* ConvertedBGImage = cvCreateImage(cvSize(CurrentImage->width, CurrentImage->height), IPL_DEPTH_32F, 3);
+
+    float* ConvertedCurrentPixel = (float*) malloc(3*(sizeof(float)));
+    float* ConvertedBGPixel = (float*) malloc(3*(sizeof(float)));
+    float* DeltaConvertedPixel = (float*) malloc(3*(sizeof(float)));
+
+    p.ColorConversion(CurrentImage,ConvertedCurrentImage,color_space);
+    p.ColorConversion(BGImage,ConvertedBGImage,color_space);
+
+    for(i = 0; i < CurrentImage->width; i++)
+    {
+      for(j = 0; j < CurrentImage->height; j++)
+      {
+        p.GetPixel(ConvertedCurrentImage,i,j,ConvertedCurrentPixel);
+        p.GetPixel(ConvertedBGImage,i,j,ConvertedBGPixel);
+        RatioPixels(ConvertedCurrentPixel,ConvertedBGPixel,DeltaConvertedPixel,3);
+        p.PutPixel(DeltaImage,i,j,DeltaConvertedPixel);
+      }
+    }
+
+    free(ConvertedCurrentPixel);
+    free(ConvertedBGPixel);
+    free(DeltaConvertedPixel);
+
+    cvReleaseImage(&ConvertedCurrentImage);
+    cvReleaseImage(&ConvertedBGImage);
+  }
+}
+
+void FuzzyUtils::RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n)
+{
+  if(n == 1)
+  {
+    if(*CurrentPixel < *BGPixel)
+      *DeltaPixel = *CurrentPixel / *BGPixel;
+
+    if(*CurrentPixel > *BGPixel)
+      *DeltaPixel = *BGPixel / *CurrentPixel;
+
+    if(*CurrentPixel == *BGPixel)
+      *DeltaPixel = 1.0;
+  }
+
+  if(n == 3)
+    for(int i = 0; i < 3; i++)
+    {
+      if(*(CurrentPixel+i) < *(BGPixel+i))
+        *(DeltaPixel+i) = *(CurrentPixel+i) / *(BGPixel+i);
+
+      if(*(CurrentPixel+i) > *(BGPixel+i))
+        *(DeltaPixel+i) = *(BGPixel+i) / *(CurrentPixel+i);
+
+      if(*(CurrentPixel+i) == *(BGPixel+i))
+        *(DeltaPixel+i) = 1.0;			
+    }
+}
+
+void FuzzyUtils::getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage)
+{
+  // MeasureG : est un vecteur contenant 3 mesure g (g1,g2,g3) tel que : g1+g2+g3=1
+  // n : =2 cad aggreger les 2 images "H" et "Delta" 
+  //	   =1 cad aggreger uniquement les valeurs des composantes couleurs de l'image "Delta"
+
+  PixelUtils p;
+
+  float* HTexturePixel = (float*) malloc(1*sizeof(float));   
+  float* DeltaOhtaPixel = (float*) malloc(3*(sizeof(float)));
+  int *Indice = (int*) malloc(3*(sizeof(int)));
+  float *HI = (float*) malloc(3*(sizeof(float)));
+  float *Integral = (float*) malloc(3*(sizeof(float)));
+  float* X = (float*) malloc(1*sizeof(float));
+  float* XiXj = (float*) malloc(1*sizeof(float));
+  float IntegralFlou;
+
+  *Indice = 0;
+  *(Indice+1) = 1;
+  *(Indice+2) = 2;
+  *X = 1.0;
+
+  for(int i = 0; i < H->width; i++)
+  {
+    for(int j = 0; j < H->height; j++)
+    {	
+      p.GetGrayPixel(H,i,j,HTexturePixel);
+      p.GetPixel(Delta,i,j,DeltaOhtaPixel);
+
+      *(HI+0) = *(HTexturePixel+0);
+      *(HI+1) = *(DeltaOhtaPixel+0);
+      *(HI+2) = *(DeltaOhtaPixel+1);
+
+      Trier(HI,3,Indice);
+
+      *XiXj = *(MeasureG + (*(Indice+1))) + (*(MeasureG + (*(Indice+2))));			
+
+      *(Integral+0) = min((HI + (*(Indice+0))), X);
+      *(Integral+1) = min((HI + (*(Indice+1))), XiXj);
+      *(Integral+2) = min((HI + (*(Indice+2))), ((MeasureG+(*(Indice+2)))));
+
+      IntegralFlou = max(Integral,3);
+      p.PutGrayPixel(OutputImage,i,j,IntegralFlou);
+    }
+  }
+
+  free(HTexturePixel);
+  free(DeltaOhtaPixel);
+  free(Indice);
+  free(HI);
+  free(X);
+  free(XiXj);
+  free(Integral);
+}
+
+void FuzzyUtils::getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage)
+{
+  // MeasureG : est un vecteur contenant 3 mesure g (g1,g2,g3) tel que : g1+g2+g3=1
+  // n : =2 cad aggreger les 2 images "H" et "Delta" 
+  //	   =1 cad aggreger uniquement les valeurs des composantes couleurs de l'image "Delta"
+
+  PixelUtils p;
+
+  float* HTexturePixel = (float*) malloc(1*sizeof(float));   
+  float* DeltaOhtaPixel = (float*) malloc(3*(sizeof(float)));
+  int *Indice = (int*) malloc(3*(sizeof(int)));
+  float *HI = (float*) malloc(3*(sizeof(float)));
+  float *Integral = (float*) malloc(3*(sizeof(float)));
+  float* X = (float*) malloc(1*sizeof(float));
+  float* XiXj = (float*) malloc(1*sizeof(float));
+  float* IntegralFlou1 = (float*) malloc(1*sizeof(float));
+  float IntegralFlou;
+
+  *Indice = 0;
+  *(Indice+1) = 1;
+  *(Indice+2) = 2;
+  *X = 1.0;
+
+  for(int i = 0; i < Delta->width; i++)
+  {
+    for(int j = 0; j < Delta->height; j++)
+    {
+      if(n == 2)
+      {
+        p.GetGrayPixel(H,i,j,HTexturePixel);
+        p.GetPixel(Delta,i,j,DeltaOhtaPixel);
+
+        *(HI+0) = *(HTexturePixel+0);
+        *(HI+1) = *(DeltaOhtaPixel+0);
+        *(HI+2) = *(DeltaOhtaPixel+1);
+      }
+
+      if(n==1)
+      {
+        //remplir HI par les valeurs des 3 composantes couleurs uniquement
+        p.GetPixel(Delta,i,j,DeltaOhtaPixel);
+
+        *(HI+0) = *(DeltaOhtaPixel+0);
+        //*(HI+0) = *(DeltaOhtaPixel+2);
+        *(HI+1) = *(DeltaOhtaPixel+1);
+        *(HI+2) = *(DeltaOhtaPixel+2);
+      }
+
+      Trier(HI,3,Indice);
+      *XiXj = *(MeasureG + (*(Indice+1))) + (*(MeasureG + (*(Indice+2))));
+
+      *(Integral+0) = *(HI+(*(Indice+0)))* (*X-*XiXj);
+      *(Integral+1) = *(HI+(*(Indice+1)))* (*XiXj-*(MeasureG+(*(Indice+2))));
+      *(Integral+2) = *(HI+(*(Indice+2)))* (*(MeasureG+(*(Indice+2))));
+
+      IntegralFlou = *(Integral+0) + *(Integral+1) + *(Integral+2);
+      p.PutGrayPixel(OutputImage,i,j,IntegralFlou);
+    }
+  }
+
+  free(HTexturePixel);
+  free(DeltaOhtaPixel);
+  free(Indice);
+  free(HI);
+  free(X);
+  free(XiXj);
+  free(Integral);
+}
+
+void FuzzyUtils::FuzzyMeasureG(float g1, float g2, float g3, float *G)
+{
+  *(G+0) = g1;
+  *(G+1) = g2;
+  *(G+2) = g3;
+}
+
+void FuzzyUtils::Trier(float* g,int n,int* index)
+{
+  // Cette fonction trie un vecteur g par ordre croissant et 
+  // sort egalement l'indice des elements selon le trie dans le vecteur "index" suppos� initialis� par des valeurs de 1 a n
+
+  float t;	
+  int r,a,b;
+
+  for(a = 1; a <= n; a++)
+  {
+    for(b = n-1; b >= a; b--)
+      if(*(g + b-1) < (*(g + b))) 
+      {
+        // ordre croissant des �lements
+        t = *(g + b-1);
+        *(g + b-1) = *(g + b);
+        *(g + b) = t;
+
+        // ordre des indices des �lements du vecteur g
+        r = *(index + b-1);
+        *(index + b-1) = *(index + b);
+        *(index + b) = r;
+      }		
+  }
+}
+
+float FuzzyUtils::min(float *a,float *b)
+{
+  float min = 0;
+
+  if(*a >= (*b)) 
+    min = *b;
+  else
+    min = *a;
+
+  return min;
+}
+
+float FuzzyUtils::max(float* g , int n)
+{
+  float max = 0;
+
+  for(int i = 0; i < n; i++)
+  {
+    if(*(g+i) >= max)
+      max = *(g+i);
+  }
+  
+  return max;
+}
+
+void FuzzyUtils::gDeDeux(float* a, float* b, float* lambda)
+{
+  float* c = (float*) malloc(1*sizeof(float));
+  *c = *a + (*b) + (*lambda) * (*a) * (*b);
+}
+
+void FuzzyUtils::getLambda(float* g)
+{
+  float a,b;
+  float* lambda = (float*) malloc(1*sizeof(float)); 
+
+  a = (*(g+0) * (*(g+1)) + (*(g+1)) * (*(g+2)) + (*(g+0)) * (*(g+2)));
+  *lambda = -(*(g+0) * (*(g+1)) + (*(g+1)) * (*(g+2)) + (*(g+0)) * (*(g+2))) / (*(g+0) * (*(g+1)) * (*(g+2)));
+  b = (*(g+0) * (*(g+1)) * (*(g+2)));
+  
+  //printf("\na:%f",a);
+  //printf("\nb:%f",b);
+  //printf("\nlambda:%f", *lambda);
+
+  free(lambda);
+}
+
+void FuzzyUtils::AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha)
+{
+  PixelUtils p;
+
+  float beta = 0.0;
+  float* CurentImagePixel = (float*) malloc(3*sizeof(float));
+  float* BGImagePixel = (float*) malloc(3*sizeof(float));
+  float* OutputImagePixel = (float*) malloc(3*sizeof(float));
+  float* IntegralImagePixel = (float*) malloc(1*sizeof(float));
+  float *Maximum = (float*) malloc(1*sizeof(float));
+  float *Minimum = (float*) malloc(1*sizeof(float));
+
+  p.ForegroundMaximum(Integral, Maximum, 1);
+  p.ForegroundMinimum(Integral, Minimum, 1);
+
+  for(int i = 0; i < CurrentImage->width; i++)
+  {
+    for(int j = 0; j < CurrentImage->height; j++)
+    {
+      p.GetPixel(CurrentImage, i, j, CurentImagePixel);
+      p.GetPixel(BGImage, i, j, BGImagePixel);
+      p.GetGrayPixel(Integral, i, j, IntegralImagePixel);
+      
+      beta = 1 - ((*IntegralImagePixel) - ((*Minimum / (*Minimum - *Maximum)) * (*IntegralImagePixel) - (*Minimum * (*Maximum) / (*Minimum - *Maximum))));
+      
+      for(int k = 0; k < 3; k++)
+        *(OutputImagePixel + k) = beta * (*(BGImagePixel + k)) + (1 - beta) * (alpha * (*(CurentImagePixel+k)) + (1-alpha) * (*(BGImagePixel+k)));
+      
+      p.PutPixel(OutputImage, i, j, OutputImagePixel);
+    }
+  }
+
+  free(CurentImagePixel);
+  free(BGImagePixel);
+  free(OutputImagePixel);
+  free(IntegralImagePixel);
+}
diff --git a/package_bgs/tb/FuzzyUtils.h b/package_bgs/tb/FuzzyUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..43fc9ad4b0fdbefb084655c7469f5a913e617050
--- /dev/null
+++ b/package_bgs/tb/FuzzyUtils.h
@@ -0,0 +1,54 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+/*
+Code provided by Thierry BOUWMANS
+
+Maitre de Conf�rences
+Laboratoire MIA
+Universit� de La Rochelle
+17000 La Rochelle
+France
+tbouwman@univ-lr.fr
+
+http://sites.google.com/site/thierrybouwmans/
+*/
+#include "PixelUtils.h"
+
+class FuzzyUtils
+{
+public:
+  FuzzyUtils(void);
+  ~FuzzyUtils(void);
+
+  void LBP(IplImage* InputImage, IplImage* LBP);
+  void getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n);
+
+  void SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space);
+  void RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n);
+
+  void getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage);
+  void getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage);
+  void FuzzyMeasureG(float g1, float g2, float g3, float *G);
+  void Trier(float* g, int n, int* index);		
+  float min(float *a, float *b);
+  float max(float *g, int n);
+  void gDeDeux(float* a, float* b, float* lambda);
+  void getLambda(float* g);
+
+  void AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha);
+};
diff --git a/package_bgs/tb/MRF.cpp b/package_bgs/tb/MRF.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1dbc69ed7993f20a3519f57c904880d8d814bd4b
--- /dev/null
+++ b/package_bgs/tb/MRF.cpp
@@ -0,0 +1,339 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "MRF.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+//init the basic MRF
+MRF::MRF()
+{
+  in_image = out_image = 0;
+  width = height = 0;
+
+  //////////////////////////////////////////////////////////////////////////
+  no_regions = 2;
+  beta = 2.8;// 0.9;
+  t = 10;//0.05
+
+  //////////////////////////////////////////////////////////////////////////
+  K = 0;
+  E = E_old = 0;
+
+  //////////////////////////////////////////////////////////////////////////
+  T0 = 4;
+  c = 0.98;
+  T = 0;
+
+  //////////////////////////////////////////////////////////////////////////
+  alpha = 0.1;
+
+  //////////////////////////////////////////////////////////////////////////
+  classes = 0;
+  in_image_data = 0;
+  local_evidence = 0;
+}
+
+/************************************************************************/
+/* the Markov Random Field with time constraints for T2FGMM    */
+/************************************************************************/
+
+MRF_TC::MRF_TC()
+{
+  beta_time = 0.9;
+}
+
+MRF_TC::~MRF_TC()
+{
+  delete []classes;
+  delete []old_labeling;
+  delete []in_image_data;
+  delete []local_evidence;
+}
+
+double MRF_TC::TimeEnergy2(int i, int j, int label)
+{
+  double energy = 0.0;
+  
+  if(old_labeling[i][j] == (label*255))
+    energy -= beta_time;
+  else
+    energy += beta_time;
+
+  if(i != height-1) // south
+  {
+    if(label*255 == old_labeling[i+1][j])
+      energy -= beta_time;
+    else
+      energy += beta_time;
+
+    if((j != width-1) && (label*255 == old_labeling[i+1][j+1]))
+      energy -= beta_time;
+    else
+      energy += beta_time;
+    
+    if((j != 0) && (label*255 == old_labeling[i+1][j-1]))
+      energy -= beta_time;
+    else
+      energy += beta_time;
+  }
+
+  if(j != width-1) // east
+  {
+    if(label*255 == old_labeling[i][j+1])
+      energy -= beta_time;
+    else
+      energy += beta_time;
+  }
+
+  if(i != 0) // nord
+  {
+    if(label*255 == old_labeling[i-1][j])
+      energy -= beta_time;
+    else
+      energy += beta_time;
+
+    if((j != width-1) && (label*255 == old_labeling[i-1][j+1]))
+      energy -= beta_time;
+    else
+      energy += beta_time;
+    
+    if((j != 0) && (label*255 == old_labeling[i-1][j-1]))
+      energy -= beta_time;
+    else
+      energy += beta_time;
+  }
+
+  if(j != 0) // west
+  {
+    if(label*255 == old_labeling[i][j-1])
+      energy -= beta_time;
+    else
+      energy += beta_time;
+  }
+
+  return energy;
+}
+
+double MRF_TC::Doubleton2(int i, int j, int label)
+{
+  double energy = 0.0;
+
+  if(i != height-1) // south
+  {
+    if(label == classes[i+1][j])
+      energy -= beta;
+    else
+      energy += beta;
+
+    if((j != width-1) && (label == classes[i+1][j+1]))
+      energy -= beta;
+    else
+      energy += beta;
+    
+    if((j != 0) && (label == classes[i+1][j-1]))
+      energy -= beta;
+    else
+      energy += beta;
+  }
+
+  if(j != width-1) // east
+  {
+    if(label == classes[i][j+1])
+      energy -= beta;
+    else
+      energy += beta;
+  }
+
+  if(i != 0) // nord
+  {
+    if(label == classes[i-1][j])
+      energy -= beta;
+    else
+      energy += beta;
+
+    if((j != width-1) && (label == classes[i-1][j+1]))
+      energy -= beta;
+    else
+      energy += beta;
+
+    if((j != 0) && (label == classes[i-1][j-1]))
+      energy -= beta;
+    else
+      energy += beta;
+  }
+
+  if(j != 0) // west
+  {
+    if(label == classes[i][j-1])
+      energy -= beta;
+    else
+      energy += beta;
+  }
+
+  return energy;
+}
+
+void MRF_TC::OnIterationOver2(void)
+{
+  CreateOutput2();
+  //cout<<"\rI="<<K<<", ";
+}
+
+void MRF_TC::Build_Classes_OldLabeling_InImage_LocalEnergy()
+{
+  int i;
+  classes = new int* [height];
+  old_labeling = new int *[height];
+  in_image_data = new int* [height];
+  local_evidence = new float* [height];
+
+  for(i = 0; i < height; ++i)
+  {
+    classes[i] = new int[width];
+    old_labeling[i] = new int[width];
+    in_image_data[i] = new int[width];
+    local_evidence[i] = new float[width*2];
+  }
+}
+
+void MRF_TC::InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling)
+{
+  int i, j;
+
+  background = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
+  cvCopyImage(background2,background.Ptr());
+
+  unsigned char *in_data = (unsigned char *)(in_image->imageData);
+  unsigned char *labeling_data = (unsigned char *)(labeling->imageData);
+
+  for(i = 0; i < height; ++i)
+  {
+    for(j = 0; j < width; ++j)
+    {
+      in_image_data[i][j] = in_data[(i*in_image->widthStep)+j];
+      old_labeling[i][j] = labeling_data[i*width+j];
+      
+      if(in_image_data[i][j] == 255)
+        classes[i][j] = 1;
+      else
+        classes[i][j] = 0;
+    }
+
+    float variance;
+    float muR;
+    float muG;
+    float muB;
+
+    float pixel;
+
+    int modes = 3;
+    float mu;	
+
+    for(i = 0; i < height; ++i)
+    {
+      for(j = 0; j < width; ++j)
+      {
+        variance = gmm[(i*width+j) * modes+0].variance;
+        muR = gmm[(i*width+j) * modes+0].muR;
+        muG = gmm[(i*width+j) * modes+0].muG;
+        muB = gmm[(i*width+j) * modes+0].muB;
+
+        mu = (muR + muG + muB)/3;
+
+        pixel = (background(i,j,0) + background(i,j,1) + background(i,j,2))/3;
+
+        if(variance == 0) variance = 1;
+
+        local_evidence[i][j*2+0] = pow((pixel-mu),2)/2/variance;
+
+        if(pixel >= mu)
+          local_evidence[i][j*2+1] = pow((pixel - mu - 2.5*sqrt(variance)),2)/2/variance;
+        else
+          local_evidence[i][j*2+1] = pow((pixel - mu + 2.5*sqrt(variance)),2)/2/variance;
+      }
+    }
+  }
+}
+
+void MRF_TC::CreateOutput2()
+{
+  int i, j;
+  unsigned char *out_data;
+
+  out_data = (unsigned char *) out_image->imageData;
+
+  // create output image
+  for (i = 0; i < height; ++i)
+    for(j = 0; j < width; ++j)
+      out_data[(i*width) + j] = (unsigned char)((classes[i][j])*255);
+}
+
+//calculate the whole energy
+double MRF_TC::CalculateEnergy2()
+{
+  double sum = 0.0;
+  int i, j, k;
+  // !FAIL!
+  for(i = 0; i < height; ++i)
+  {
+    for(j = 0; j < width; ++j)
+    {
+      k = classes[i][j];
+      sum = sum + local_evidence[i][j*2+k] + Doubleton2(i,j,k) + TimeEnergy2(i, j, k);//min the value
+    }
+  }
+  //sum = 0.1;
+  return sum;
+}
+
+// local energy
+double MRF_TC::LocalEnergy2(int i, int j, int label)
+{
+  return local_evidence[i][j*2+label] + Doubleton2(i,j,label) + TimeEnergy2(i,j,label);
+}
+
+void MRF_TC::ICM2()
+{
+  int i, j;
+  int r;
+  //double summa_deltaE = 0;
+  double localenergy0 = 0, localenergy1 = 0;
+
+  K = 0;
+  //E_old = CalculateEnergy2();
+
+  do
+  {
+    for(i = 0; i < height; ++i)
+      for(j = 0; j < width; ++j)
+      {
+        localenergy0 = LocalEnergy2(i,j,0);
+        localenergy1 = LocalEnergy2(i,j,1);
+        
+        if(localenergy0 < localenergy1)
+          classes[i][j] = 0;
+        else
+          classes[i][j] = 1;
+      }
+
+      //E = CalculateEnergy2();
+      //summa_deltaE = fabs(E_old-E);
+      //E_old = E;
+      ++K;
+      OnIterationOver2();
+  }while(K < 2);
+}
diff --git a/package_bgs/tb/MRF.h b/package_bgs/tb/MRF.h
new file mode 100644
index 0000000000000000000000000000000000000000..457bbbc600c81486a7c1c60ffc7c7d664f29065c
--- /dev/null
+++ b/package_bgs/tb/MRF.h
@@ -0,0 +1,107 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef MRF_H
+#define MRF_H
+
+#include "T2FMRF.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    // base class
+    class MRF
+    {
+    public:
+      IplImage *in_image, *out_image;
+      //image's width and height
+      int width, height;
+
+    public:
+      MRF();
+
+    protected:
+
+      //////////////////////////////////////////////////////////////////////////
+      //the number of labeling
+      int no_regions;
+      //potential of Space  Constraint
+      double beta;
+      //terminal condition when (deltaE < t)
+      double t;
+
+      //////////////////////////////////////////////////////////////////////////
+      //for gibbs
+      double T0;
+      //current temperature
+      double T;
+      double c;
+
+      //////////////////////////////////////////////////////////////////////////
+      // alpha value for MMD
+      double alpha;		            
+
+      //////////////////////////////////////////////////////////////////////////
+      //current global energy
+      double E;
+      //old global energy
+      double E_old;
+      //number of iteration
+      int K;
+
+      //////////////////////////////////////////////////////////////////////////
+      //labeling image 
+      int **classes;
+      //input image
+      int **in_image_data;
+      //evidence
+      float ** local_evidence;
+    };
+
+    /************************************************************************/
+    /* the Markov Random Field with time constraints for T2FGMM   */
+    /************************************************************************/
+    class MRF_TC: public MRF
+    {
+    private:
+      double beta_time;
+
+    public:
+      IplImage *background2;
+      RgbImage background;
+      int **old_labeling;
+
+    public:
+      MRF_TC();
+      ~MRF_TC();
+      double TimeEnergy2(int i, int j, int label);
+      void OnIterationOver2(void);
+      void Build_Classes_OldLabeling_InImage_LocalEnergy();
+      void InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling);
+      void CreateOutput2();
+      double CalculateEnergy2();
+      double LocalEnergy2(int i, int j, int label);
+      double Doubleton2(int i, int j, int label);
+
+      void Gibbs2();
+      void ICM2();
+      void Metropolis2(bool mmd);
+    };
+  };
+};
+
+#endif
\ No newline at end of file
diff --git a/package_bgs/tb/PerformanceUtils.cpp b/package_bgs/tb/PerformanceUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..30f89b774a8e6959c23cde6f8bb45a036325d13e
--- /dev/null
+++ b/package_bgs/tb/PerformanceUtils.cpp
@@ -0,0 +1,521 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "PerformanceUtils.h"
+
+PerformanceUtils::PerformanceUtils(void){}
+
+PerformanceUtils::~PerformanceUtils(void){}
+
+float PerformanceUtils::NrPixels(IplImage *image)
+{
+  return (float) (image->width * image->height);
+}
+
+float PerformanceUtils::NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth)
+{
+  //Nombre de tous les pixels non nuls dans Groundthruth et dans image
+  float Union12 = 0.0;
+
+  unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char));
+  unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char));
+
+  PixelUtils p;
+
+  for(int y = 0; y < image->height; y++) 
+  {
+    for(int x = 0; x < image->width; x++) 
+    { 
+      p.GetGrayPixel(ground_truth,x,y,pixelGT); 
+      p.GetGrayPixel(image,x,y,pixelI);
+
+      if((pixelGT[0] != 0) || (pixelI[0] != 0))	
+        Union12++;
+    }
+  }
+
+  free(pixelGT);
+  free(pixelI);
+
+  return Union12;	
+}
+
+float PerformanceUtils::NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug)
+{
+  float nTP = 0.0;
+
+  unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char));
+  unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char));
+
+  IplImage *TPimage = 0;
+
+  if(debug)
+  {
+    TPimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels);
+    cvFillImage(TPimage,0.0);
+  }
+
+  PixelUtils p;
+
+  for(int y = 0; y < image->height; y++) 
+  {
+    for(int x = 0; x < image->width; x++) 
+    { 
+      p.GetGrayPixel(ground_truth,x,y,pixelGT); 
+      p.GetGrayPixel(image,x,y,pixelI);
+
+      if((pixelGT[0] != 0) && (pixelI[0] != 0))	
+      {
+        if(debug)
+          p.PutGrayPixel(TPimage,x,y,*pixelI);
+
+        nTP++;
+      }
+    }
+  }
+
+  if(debug)
+  {
+    cvNamedWindow("TPImage", 0);
+    cvShowImage("TPImage", TPimage);
+    //std::cout << "True Positives: " << nTP << std::endl;
+    //<< " press ENTER to continue" << std::endl;
+    //cvWaitKey(0);
+    cvReleaseImage(&TPimage);
+  }
+
+  free(pixelGT);
+  free(pixelI);
+
+  return nTP;	
+}
+
+float PerformanceUtils::NrTrueNegatives(IplImage* image, IplImage* ground_truth, bool debug)
+{
+  float nTN = 0.0;
+
+  unsigned char *pixelGT = (unsigned char *)malloc(1*sizeof(unsigned char));
+  unsigned char *pixelI = (unsigned char *)malloc(1*sizeof(unsigned char));
+
+  IplImage *TNimage = 0;
+
+  if(debug)
+  {
+    TNimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels);
+    cvFillImage(TNimage, 0.0);
+  }
+
+  PixelUtils p;
+
+  for(int y = 0; y < image->height; y++) 
+  {
+    for(int x = 0; x < image->width; x++) 
+    {
+      p.GetGrayPixel(ground_truth,x,y,pixelGT);                
+      p.GetGrayPixel(image,x,y,pixelI);
+
+      if((pixelGT[0] == 0) && (pixelI[0] == 0.0))
+      {
+        *pixelI = 255;
+
+        if(debug)
+          p.PutGrayPixel(TNimage,x,y,*pixelI);
+
+        nTN++;
+      }				
+    }
+  }
+
+  if(debug)
+  {
+    cvNamedWindow("TNImage", 0);
+    cvShowImage("TNImage", TNimage);
+    //std::cout << "True Negatives: " << nTN << std::endl;
+    //<< " press ENTER to continue" << std::endl;
+    //cvWaitKey(0);
+    cvReleaseImage(&TNimage);
+  }
+
+  free(pixelGT);
+  free(pixelI);
+
+  return nTN;
+}
+
+float PerformanceUtils::NrFalsePositives(IplImage *image, IplImage *ground_truth,bool debug)
+{
+  float nFP = 0.0;
+
+  unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char));
+  unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char));
+
+  IplImage *FPimage = 0;
+
+  if(debug)
+  {
+    FPimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels);
+    cvFillImage(FPimage, 0.0);
+  }
+
+  PixelUtils p;
+
+  for(int y = 0; y < image->height; y++) 
+  {
+    for(int x = 0; x < image->width; x++) 
+    {
+      p.GetGrayPixel(ground_truth,x,y,pixelGT);                
+      p.GetGrayPixel(image,x,y,pixelI);
+
+      if((pixelGT[0] == 0) && (pixelI[0] != 0))
+      {
+        if(debug)
+          p.PutGrayPixel(FPimage,x,y,*pixelI);
+
+        nFP++;
+      }
+    }
+  }
+
+  if(debug)
+  {
+    cvNamedWindow("FPImage", 0);
+    cvShowImage("FPImage", FPimage);
+    //std::cout << "False Positives: " << nFP << std::endl;
+    //<< " press ENTER to continue" << std::endl;
+    //cvWaitKey(0);
+    cvReleaseImage(&FPimage);
+  }
+
+  free(pixelGT);
+  free(pixelI);
+
+  return nFP;	
+}
+
+float PerformanceUtils::NrFalseNegatives(IplImage * image, IplImage *ground_truth, bool debug)
+{
+  float nFN = 0.0;
+
+  unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char));
+  unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char));
+
+  IplImage *FNimage = 0;
+
+  if(debug)
+  {
+    FNimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels);
+    cvFillImage(FNimage, 0.0);
+  }
+
+  PixelUtils p;
+
+  for(int y = 0; y < image->height; y++) 
+  {
+    for(int x = 0; x < image->width; x++) 
+    {
+      p.GetGrayPixel(ground_truth,x,y,pixelGT);
+      p.GetGrayPixel(image,x,y,pixelI);
+
+      if((pixelGT[0] != 0) && (pixelI[0] == 0))
+      {
+        if(debug)
+          p.PutGrayPixel(FNimage,x,y,*pixelGT);
+
+        nFN++;
+      }
+    }
+  }
+
+  if(debug)
+  {
+    cvNamedWindow("FNImage", 0);
+    cvShowImage("FNImage", FNimage);
+    //std::cout << "False Negatives: " << nFN << std::endl;
+    //<< " press ENTER to continue" << std::endl;
+    //cvWaitKey(0);
+    cvReleaseImage(&FNimage);
+  }
+
+  free(pixelGT);
+  free(pixelI);
+
+  return nFN;	
+}
+
+float PerformanceUtils::SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug)
+{
+  cv::Mat img_input(image,true);
+  cv::Mat img_ref(ground_truth,true);
+
+  int rn = cv::countNonZero(img_ref);
+  cv::Mat i;
+  cv::Mat u;
+
+  if(rn > 0)
+  {
+    i = img_input & img_ref;
+    u = img_input | img_ref;
+  }
+  else
+  {
+    i = (~img_input) & (~img_ref);
+    u = (~img_input) | (~img_ref);
+  }
+
+  int in = cv::countNonZero(i);
+  int un = cv::countNonZero(u);
+    
+  double s = (((double)in) / ((double)un));
+  
+  if(debug)
+  {
+    cv::imshow("A^B", i);
+    cv::imshow("AvB", u);
+
+    //std::cout << "Similarity Measure: " << s  << std::endl;
+    
+    //<< " press ENTER to continue" << std::endl;
+    //cv::waitKey(0);
+  }
+
+  return s;
+}
+
+void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults, char* filename)
+{
+  unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char));
+  unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char));
+
+  IplImage *ROCimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels);
+  cvFillImage(ROCimage, 0.0);
+
+  PixelUtils p;
+
+  for(int y = 0; y < image->height; y++) 
+  {
+    for(int x = 0; x < image->width; x++) 
+    {
+      p.GetGrayPixel(ground_truth,x,y,pixelGT);                
+      p.GetGrayPixel(image,x,y,pixelI);
+
+      if((pixelGT[0] != 0) && (pixelI[0] != 0)) // TP
+      {
+        *pixelI = 30;
+        p.PutGrayPixel(ROCimage,x,y,*pixelI);
+      }
+
+      if((pixelGT[0] == 0) && (pixelI[0] == 0.0)) // TN
+      {
+        *pixelI = 0;
+        p.PutGrayPixel(ROCimage,x,y,*pixelI);
+      }	
+
+      if((pixelGT[0] == 0) && (pixelI[0] != 0)) // FP
+      {
+        *pixelI = 255;
+        p.PutGrayPixel(ROCimage,x,y,*pixelI);
+      }
+
+      if((pixelGT[0] != 0) && (pixelI[0] == 0)) // FN
+      {
+        *pixelI = 100;
+        p.PutGrayPixel(ROCimage,x,y,*pixelI);
+      }
+    }
+  }
+
+  cvNamedWindow("ROC image", 0);
+  cvShowImage("ROC image", ROCimage);
+
+  if(saveResults)
+  {
+    unsigned char *pixelOI = (unsigned char*) malloc(1*sizeof(unsigned char));
+    unsigned char *pixelROC = (unsigned char*) malloc(1*sizeof(unsigned char));
+
+    float** freq;
+    float nTP = 0.0;
+    float nTN = 0.0;
+    float nFP = 0.0;
+    float nFN = 0.0;
+
+    freq = (float**) malloc(256*(sizeof(float*)));
+    for(int i = 0; i < 256; i++)
+      freq[i] = (float*) malloc(7 * (sizeof(float)));
+
+    for(int i = 0; i < 256; i++)
+      for(int j = 0; j < 6; j++) 
+        freq[i][j] = 0.0;
+
+    for(int y = 0; y < image->height; y++)
+    {
+      for(int x = 0; x < image->width; x++) 
+      {
+        for(int i = 0; i < 256; i++)
+        {
+          p.GetGrayPixel(image,x,y,pixelOI);                
+          p.GetGrayPixel(ROCimage,x,y,pixelROC);
+
+          if((pixelOI[0] == i) && (pixelROC[0] == 30.0)) // TP
+          {
+            nTP++;
+            freq[i][0] = nTP;
+            break;
+          }
+
+          if((pixelOI[0] == i) && (pixelROC[0] == 0.0)) // TN
+          {
+            nTN++;
+            freq[i][1] = nTN;
+            break;
+          }
+
+          if((pixelOI[0] == i) && (pixelROC[0] == 255.0)) // FP
+          {
+            nFP++;
+            freq[i][2] = nFP;
+            break;
+          }
+
+          if((pixelOI[0] == i) && (pixelROC[0] == 100)) // FN
+          {
+            nFN++;
+            freq[i][3] = nFN;
+            break;
+          }
+        }
+      }
+    }
+
+    //freq[i][0] = TP
+    //freq[i][1] = TN
+    //freq[i][2] = FP
+    //freq[i][3] = FN
+    //freq[i][4] = FNR
+    //freq[i][5] = FPR
+
+    std::ofstream f(filename);
+
+    if(!f.is_open())
+      std::cout << "Failed to open file " << filename << " for writing!" << std::endl;
+    else
+    {
+      f << "  I     TP     TN     FP     FN    FPR      FNR      DR   \n" << std::endl;
+      
+      for(int i = 0; i < 256; i++)
+      {
+        //printf("%4d - TP:%5.0f, TN:%5.0f, FP:%5.0f, FN:%5.0f,", i, freq[i][0], freq[i][1], freq[i][2], freq[i][3]);
+
+        if((freq[i][3] + freq[i][0] != 0.0) && (freq[i][2] + freq[i][1] != 0.0))
+        {
+          freq[i][4] = freq[i][3] / (freq[i][3] + freq[i][0]);  // FNR = FN / (TP + FN);
+          freq[i][5] = freq[i][2] / (freq[i][2] + freq[i][1]);	// FPR = FP / (FP + TN);
+          freq[i][6] = freq[i][0] / (freq[i][0] + freq[i][3]);	// DR = TP / (TP+FN);
+
+          //printf(" FPR:%1.5f, FNR:%1.5f, D:%1.5f\n", freq[i][5], freq[i][4], freq[i][6]);
+          ////fprintf(f," %4d     %1.6f     %1.6f\n",i,freq[i][5],freq[i][4]);
+          ////fprintf(f,"  %1.6f     %1.6f\n",freq[i][5],freq[i][4]);
+          char line[255];
+          sprintf(line,"%3d %6.0f %6.0f %6.0f %6.0f %1.6f %1.6f %1.6f\n", 
+            i, freq[i][0], freq[i][1], freq[i][2], freq[i][3], freq[i][5], freq[i][4], freq[i][6]);
+          f << line;
+        }
+        //else
+          //printf("\n");
+      }
+
+      std::cout << "Results saved in " << filename << std::endl;
+      f.close();
+    }
+
+    free(freq);
+    free(pixelOI);
+    free(pixelROC);
+  }
+
+  //std::cout << "press ENTER to continue" << std::endl;
+  //cvWaitKey(0);
+  cvReleaseImage(&ROCimage);
+
+  free(pixelGT);
+  free(pixelI);
+}
+
+void PerformanceUtils::PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults, char* filename, bool debug)
+{
+  float N = 0;
+  N = NrPixels(image);
+
+  float U = 0;
+  U = NrAllDetectedPixNotNULL(image, ground_truth);
+  
+  float TP = 0;
+  TP = NrTruePositives(image, ground_truth, debug);
+  
+  float TN = 0;
+  TN = NrTrueNegatives(image, ground_truth, debug);
+  
+  float FP = 0;
+  FP = NrFalsePositives(image, ground_truth, debug);
+  
+  float FN = 0;
+  FN = NrFalseNegatives(image, ground_truth, debug);
+  
+  float DetectionRate = TP / (TP + FN);
+  float Precision = TP / (TP + FP);
+  float Fmeasure = (2 * DetectionRate * Precision) / (DetectionRate + Precision);
+
+  float Accuracy = (TN + TP) / N;
+  float FalseNegativeRate = FN / (TP + FN);
+  
+  float FalsePositiveRate = FP / (FP + TN);
+  float TruePositiveRate = TP / (TP + FN);
+  
+  float SM = 0;
+  SM = SimilarityMeasure(image, ground_truth, debug);
+
+  std::stringstream sstm;
+  sstm << "N = " << N << std::endl;
+  sstm << "U = " << U << std::endl;
+  sstm << "TP = " << TP << std::endl;
+  sstm << "TN = " << TN << std::endl;
+  sstm << "FP = " << FP << std::endl;
+  sstm << "FN = " << FN << std::endl;
+  sstm << "DetectionRate     = " << DetectionRate << std::endl;
+  sstm << "Precision         = " << Precision << std::endl;
+  sstm << "Fmeasure          = " << Fmeasure << std::endl;
+  sstm << "Accuracy          = " << Accuracy << std::endl;
+  sstm << "FalseNegativeRate = " << FalseNegativeRate << std::endl;
+  sstm << "FalsePositiveRate = " << FalsePositiveRate << std::endl;
+  sstm << "TruePositiveRate  = " << TruePositiveRate << std::endl;
+  sstm << "SimilarityMeasure = " << SM << std::endl;
+
+  std::string results = sstm.str();
+  std::cout << results;
+
+  if(saveResults)
+  {
+    std::ofstream f(filename);
+
+    if(!f.is_open())
+      std::cout << "Failed to open file " << filename << " for writing!" << std::endl;
+    else
+    {
+      f << results;
+      std::cout << "Results saved in " << filename << std::endl;
+      f.close();
+    }
+  }
+}
\ No newline at end of file
diff --git a/package_bgs/tb/PerformanceUtils.h b/package_bgs/tb/PerformanceUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..c60826422aab262d37aa4d7edde841e00cc4cdf8
--- /dev/null
+++ b/package_bgs/tb/PerformanceUtils.h
@@ -0,0 +1,54 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+/*
+Code provided by Thierry BOUWMANS
+
+Maitre de Conf�rences
+Laboratoire MIA
+Universit� de La Rochelle
+17000 La Rochelle
+France
+tbouwman@univ-lr.fr
+
+http://sites.google.com/site/thierrybouwmans/
+*/
+#include <stdio.h>
+#include <fstream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "PixelUtils.h"
+
+class PerformanceUtils
+{
+public:
+  PerformanceUtils(void);
+  ~PerformanceUtils(void);
+
+  float NrPixels(IplImage *image);
+  float NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth);
+  float NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug = false);
+  float NrTrueNegatives(IplImage *image, IplImage *ground_truth, bool debug = false);
+  float NrFalsePositives(IplImage *image, IplImage *ground_truth, bool debug = false);
+  float NrFalseNegatives(IplImage *image, IplImage *ground_truth, bool debug = false);
+  float SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug = false);
+
+  void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, char* filename = "");
+  void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, char* filename = "", bool debug = false);
+};
+
diff --git a/package_bgs/tb/PixelUtils.cpp b/package_bgs/tb/PixelUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc61cc5f738e5184b08e475f3f96128a74050ffd
--- /dev/null
+++ b/package_bgs/tb/PixelUtils.cpp
@@ -0,0 +1,351 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "PixelUtils.h"
+
+PixelUtils::PixelUtils(void){}
+PixelUtils::~PixelUtils(void){}
+
+void PixelUtils::ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space)
+{
+  // Space Color RGB - Nothing to do!
+  if(color_space == 1)
+    cvCopyImage(RGBImage, ConvertedImage);
+
+  // Space Color Ohta
+  if(color_space == 2) 
+    cvttoOTHA(RGBImage, ConvertedImage);
+
+  // Space Color HSV - V Intensity - (H,S) Chromaticity
+  if(color_space == 3)
+    cvCvtColor(RGBImage, ConvertedImage, CV_BGR2HSV);
+
+  // Space Color YCrCb - Y Intensity - (Cr,Cb) Chromaticity
+  if(color_space == 4)
+    cvCvtColor(RGBImage,ConvertedImage,CV_BGR2YCrCb);
+}
+
+void PixelUtils::cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage)
+{
+  float* OhtaPixel = (float*) malloc(3*(sizeof(float)));
+  float* RGBPixel = (float*) malloc(3*(sizeof(float)));
+
+  for(int i = 0; i < RGBImage->width; i++)
+  {
+    for(int j = 0;j < RGBImage->height; j++)
+    {
+      GetPixel(RGBImage, i, j, RGBPixel);
+
+      // I1 = (R + G + B) / 3
+      *OhtaPixel = (*(RGBPixel) + (*(RGBPixel + 1)) + (*(RGBPixel + 2))) / 3.0;
+
+      // I2 = (R - B) / 2
+      *(OhtaPixel+1) = (*RGBPixel - (*(RGBPixel + 2))) / 2.0;
+
+      // I3 = (2G - R - B) / 4
+      *(OhtaPixel+2) = (2 * (*(RGBPixel + 1)) - (*RGBPixel) - (*(RGBPixel + 2))) / 4.0;		
+      
+      PutPixel(OthaImage, i, j, OhtaPixel);
+    }
+  }
+
+  free(OhtaPixel);
+  free(RGBPixel);
+}
+
+void PixelUtils::PostProcessing(IplImage *InputImage)
+{
+  IplImage *ResultImage = cvCreateImage(cvSize(InputImage->width, InputImage->height), IPL_DEPTH_32F, 3);
+
+  cvErode(InputImage, ResultImage, NULL, 1);
+  cvDilate(ResultImage, InputImage, NULL, 0);
+
+  cvReleaseImage(&ResultImage);
+}	
+
+void PixelUtils::GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant)
+{	
+  for(int k = 0; k < 3; k++)
+    pixelcourant[k] = ((unsigned char*)(image->imageData + image->widthStep*n))[m*3 + k];
+}
+
+void PixelUtils::GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant)
+{	
+  *pixelcourant = ((unsigned char*)(image->imageData + image->widthStep*n))[m];
+}
+
+void PixelUtils::PutPixel(IplImage *image,int p,int q,unsigned char *pixelcourant)
+{	
+  for(int r = 0; r < 3; r++)
+    ((unsigned char*)(image->imageData + image->widthStep*q))[p*3 + r] = pixelcourant[r];
+}
+
+void PixelUtils::PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant)
+{	
+  ((unsigned char*)(image->imageData + image->widthStep*q))[p] = pixelcourant; 
+}
+
+void PixelUtils::GetPixel(IplImage *image, int m, int n, float *pixelcourant)
+{	
+  for(int k = 0; k < 3; k++)
+    pixelcourant[k] = ((float*)(image->imageData + image->widthStep*n))[m*3 + k];
+}
+
+void PixelUtils::GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant)
+{	
+  *pixelcourant = ((float*)(image->imageData + image->widthStep*n))[m];
+}
+
+void PixelUtils::PutPixel(IplImage *image, int p, int q, float *pixelcourant)
+{	
+  for(int r = 0; r < 3; r++)
+    ((float*)(image->imageData + image->widthStep*q))[p*3 + r] = pixelcourant[r];
+}
+
+void PixelUtils::PutGrayPixel(IplImage *image,int p,int q,float pixelcourant)
+{	
+  ((float*)(image->imageData + image->widthStep*q))[p] = pixelcourant;
+}
+
+void PixelUtils::getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel)
+{
+  int i,j,k;
+  
+  float* pixelCourant = (float*) malloc(1*(sizeof(float)));
+  
+  //le calcul de voisinage pour les 4 coins;
+  /* 1.*/
+  if(x==0 && y==0)
+  {
+    k = 0;
+    for(i = x; i < x+2; i++)
+      for(j = y; j < y+2; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }
+
+  /* 2.*/
+  if(x==0 && y==InputImage->width)
+  {
+    k = 0;
+    for(i = x; i < x+2; i++)
+      for(j = y-1; j < y+1; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }
+
+  /* 3.*/
+  if(x==InputImage->height && y==0)
+  {
+    k = 0;
+    for(i = x-1; i < x+1; i++)
+      for(j = y; j < y+2; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }	
+
+  /* 4.*/
+  if(x==InputImage->height && y==InputImage->width)
+  {
+    k = 0;
+    for(i = x-1; i <x+1; i++)
+      for(j = y-1; j < y+1; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }	
+
+  // Voisinage de la premiere ligne : L(0) 
+  if(x==0 && (y!=0 && y!=InputImage->width)) 
+  {
+    k = 0;
+    for(i = x+1; i >= x; i--)
+      for(j = y-1; j < y+2; j++)
+      {
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }
+
+  // Voisinage de la derni�re colonne : C(w)
+  if((x!=0 && x!=InputImage->height) && y==InputImage->width) 
+  {
+    k = 0;
+    for(i = x+1; i > x-2; i--)
+      for(j = y-1; j < y+1; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }
+
+  // Voisinage de la derni�re ligne : L(h)    
+  if(x==InputImage->height && (y!=0 && y!=InputImage->width)) 
+  {
+    k = 0;
+    for(i = x; i > x-2; i--)
+      for(j = y-1; j < y+2; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }
+
+  // Voisinage de la premiere colonne : C(0) 
+  if((x!=0 && x!=InputImage->height) && y==0) 
+  {
+    k = 0;
+    for(i = x-1; i < x+2; i++)
+      for(j = y; j < y+2; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }  
+
+  //le calcul du voisinage pour le reste des elementes d'image
+  if((x!=0 && x!=InputImage->height)&&(y!=0 && y!=InputImage->width))
+  {
+    k = 0; 
+    for(i = x+1;i > x-2; i--)
+      for(j = y-1; j < y+2; j++)
+      {  
+        GetGrayPixel(InputImage,i,j,pixelCourant);
+        *(neighberPixel+k) = *pixelCourant;
+        k++;
+      }
+  }
+
+  free(pixelCourant);
+}
+
+void PixelUtils::ForegroundMinimum(IplImage *Foreground, float *Minimum, int n)
+{
+  int i,j,k;
+  float *pixelcourant;
+  
+  pixelcourant = (float *) malloc(n*sizeof(float));
+  
+  for(k = 0; k < n; k++)
+    *(Minimum + k) = 255;
+
+  for(i = 0; i < Foreground->width; i++)
+    for(j = 0; j < Foreground->height; j++)
+    {
+      if(n == 3)
+      {
+        GetPixel(Foreground,i,j,pixelcourant);
+
+        for(k = 0; k < n; k++)
+          if(*(pixelcourant + k) < *(Minimum + k))
+            *(Minimum + k) = *(pixelcourant + k);
+      }
+
+      if(n==1)
+      {
+        GetGrayPixel(Foreground,i,j,pixelcourant);
+
+        if(*pixelcourant < *Minimum)
+          *Minimum = *pixelcourant;
+      }
+    }
+
+    free(pixelcourant);
+}
+
+void PixelUtils::ForegroundMaximum(IplImage *Foreground, float *Maximum, int n)
+{
+  int i,j,k;
+  float *pixelcourant;
+  
+  pixelcourant = (float *) malloc(n*sizeof(float));
+  
+  for(k = 0; k < n; k++)
+    *(Maximum + k) = 0;
+  
+  for(i = 0; i < Foreground->width; i++)
+    for(j = 0; j < Foreground->height; j++)
+    {
+      if(n == 3)
+      {
+        GetPixel(Foreground,i,j,pixelcourant);
+
+        for(k = 0; k < n; k++)
+          if(*(pixelcourant + k) > *(Maximum + k))
+            *(Maximum + k) = *(pixelcourant + k);
+      }
+
+      if(n == 1)
+      {
+        GetGrayPixel(Foreground,i,j,pixelcourant);
+
+        if(*pixelcourant > *Maximum)
+          *Maximum = *pixelcourant;
+      }
+    }
+
+    free(pixelcourant);
+}
+
+void PixelUtils::ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n)
+{
+  int i,j,k;
+  float *pixelcourant, *pixelcourant1;
+  
+  pixelcourant = (float *) malloc(n * sizeof(float));
+  pixelcourant1 = (float *) malloc(n * sizeof(float));
+
+  for(i = 0; i < AlphaImage->width; i++)
+    for(j = 0; j < AlphaImage->height; j++)
+    {
+      if(n == 1)
+      {
+        GetGrayPixel(AlphaImage,i,j,pixelcourant);
+        *pixelcourant1 = 1 - *(pixelcourant);
+        PutGrayPixel(ComplementaryAlphaImage,i,j,*pixelcourant1);
+      }
+
+      if(n == 3)
+      {
+        GetPixel(AlphaImage,i,j,pixelcourant);
+        for(k = 0; k < 3; k++)
+        {
+          *pixelcourant1 = 1.0 - *(pixelcourant);
+          *(pixelcourant1+1) = 1.0 - *(pixelcourant+1);
+          *(pixelcourant1+2) = 1.0 - *(pixelcourant+2);
+        }
+        PutPixel(ComplementaryAlphaImage,i,j,pixelcourant1);
+      }
+    }
+
+    free(pixelcourant);
+    free(pixelcourant1);
+}
diff --git a/package_bgs/tb/PixelUtils.h b/package_bgs/tb/PixelUtils.h
new file mode 100644
index 0000000000000000000000000000000000000000..efbfdd9c9c3d5af95329a5fc0ce51659578e357f
--- /dev/null
+++ b/package_bgs/tb/PixelUtils.h
@@ -0,0 +1,61 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+/*
+Code provided by Thierry BOUWMANS
+
+Maitre de Conf�rences
+Laboratoire MIA
+Universit� de La Rochelle
+17000 La Rochelle
+France
+tbouwman@univ-lr.fr
+
+http://sites.google.com/site/thierrybouwmans/
+*/
+#include <stdio.h>
+#include <cv.h>
+#include <highgui.h>
+
+class PixelUtils
+{
+public:
+  PixelUtils(void);
+  ~PixelUtils(void);
+
+  void ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space);
+  void cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage);
+  
+  void PostProcessing(IplImage *InputImage);
+  
+  void GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant);
+  void GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant);
+
+  void PutPixel(IplImage *image, int p, int q, unsigned char *pixelcourant);
+  void PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant);
+
+  void GetPixel(IplImage *image, int m, int n, float *pixelcourant);
+  void GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant);
+
+  void PutPixel(IplImage *image, int p, int q, float *pixelcourant);
+  void PutGrayPixel(IplImage *image, int p, int q, float pixelcourant);
+
+  void getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel);
+  void ForegroundMaximum(IplImage *Foreground, float *Maximum, int n);
+  void ForegroundMinimum(IplImage *Foreground, float *Minimum, int n);
+  void ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n);
+};
\ No newline at end of file
diff --git a/package_bgs/tb/T2FGMM.cpp b/package_bgs/tb/T2FGMM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..70d5749c32bb6b765cc51b0a1a263f5936b5b6d2
--- /dev/null
+++ b/package_bgs/tb/T2FGMM.cpp
@@ -0,0 +1,337 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* T2FGMM.cpp
+* 
+* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) 
+* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models"
+* Author: Fida El Baf, Thierry Bouwmans, September 2008.
+
+******************************************************************************/
+
+#include "T2FGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+int compareT2FGMM(const void* _gmm1, const void* _gmm2)
+{
+  GMM gmm1 = *(GMM*)_gmm1;
+  GMM gmm2 = *(GMM*)_gmm2;
+
+  if(gmm1.significants < gmm2.significants)
+    return 1;
+  else if(gmm1.significants == gmm2.significants)
+    return 0;
+  else
+    return -1;
+}
+
+T2FGMM::T2FGMM()
+{
+  m_modes = NULL;
+}
+
+T2FGMM::~T2FGMM()
+{
+  if(m_modes != NULL) 
+    delete[] m_modes;
+}
+
+void T2FGMM::Initalize(const BgsParams& param)
+{
+  m_params = (T2FGMMParams&) param;
+
+  // Tbf - the threshold
+  m_bg_threshold = 0.75f;	// 1-cf from the paper 
+
+  // Tgenerate - the threshold
+  m_variance = 36.0f;		// sigma for the new mode
+
+  // GMM for each pixel
+  m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
+
+  // used modes per pixel
+  m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
+
+  m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+
+  // Factor control for the T2FGMM-UM [0,3]
+  //km = (float) 1.5;
+  km = (float) m_params.KM();
+
+  // Factor control for the T2FGMM-UV [0.3,1]
+  //kv = (float) 0.6;
+  kv = (float) m_params.KV();
+}
+
+RgbImage* T2FGMM::Background()
+{
+  return &m_background;
+}
+
+void T2FGMM::InitModel(const RgbImage& data)
+{
+  m_modes_per_pixel.Clear();
+
+  for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+  {
+    m_modes[i].weight = 0;
+    m_modes[i].variance = 0;
+    m_modes[i].muR = 0;
+    m_modes[i].muG = 0;
+    m_modes[i].muB = 0;
+    m_modes[i].significants = 0;
+  }
+}
+
+void T2FGMM::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+  // it doesn't make sense to have conditional updates in the GMM framework
+}
+
+void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, 
+                           unsigned char& low_threshold, unsigned char& high_threshold)
+{
+  // calculate distances to the modes (+ sort???)
+  // here we need to go in descending order!!!
+  long pos;
+  bool bFitsPDF = false;
+  bool bBackgroundLow = false;
+  bool bBackgroundHigh = false;
+
+  float fOneMinAlpha = 1 - m_params.Alpha();
+  float totalWeight = 0.0f;
+
+  // calculate number of Gaussians to include in the background model
+  int backgroundGaussians = 0;
+  double sum = 0.0;
+  for(int i = 0; i < numModes; ++i)
+  {
+    if(sum < m_bg_threshold)
+    {
+      backgroundGaussians++;
+      sum += m_modes[posPixel+i].weight;
+    }
+    else
+      break;
+  }
+
+  // update all distributions and check for match with current pixel
+  for(int iModes = 0; iModes < numModes; iModes++)
+  {
+    pos = posPixel + iModes;
+    float weight = m_modes[pos].weight;
+
+    // fit not found yet
+    if (!bFitsPDF)
+    {
+      //check if it belongs to some of the modes
+      //calculate distance
+      float var = m_modes[pos].variance;
+      float muR = m_modes[pos].muR;
+      float muG = m_modes[pos].muG;
+      float muB = m_modes[pos].muB;
+
+      //float km = 2;
+      //float kv = 0.9;
+
+      float dR = fabs(muR - pixel(0));
+      float dG = fabs(muG - pixel(1));
+      float dB = fabs(muB - pixel(2));
+
+      // calculate the squared distance
+      float HR;
+      float HG;
+      float HB;
+
+      // T2FGMM-UM
+      if(m_params.Type() == TYPE_T2FGMM_UM)
+      {
+        if((pixel(0)<muR-km*var)|| (pixel(0)>muR+km*var))
+          HR=2*km*dR/var;
+        else
+          HR=dR*dR/(2*var*var)+km*dR/var+km*km/2;
+
+        if((pixel(1)<muG-km*var)|| (pixel(1)>muG+km*var))
+          HG=2*km*dG/var;
+        else
+          HG=dG*dG/(2*var*var)+km*dG/var+km*km/2;
+
+        if((pixel(2)<muB-km*var)|| (pixel(2)>muB+km*var))
+          HB=2*km*dB/var;
+        else
+          HB=dB*dB/(2*var*var)+km*dB/var+km*km/2;
+      }
+
+      // T2FGMM-UV
+      if(m_params.Type() == TYPE_T2FGMM_UV)
+      {
+        HR = (1/(kv*kv)-kv*kv) * (pixel(0)-muR) * (pixel(0)-muR)/(2*var);
+        HG = (1/(kv*kv)-kv*kv) * (pixel(1)-muG) * (pixel(1)-muG)/(2*var);
+        HB = (1/(kv*kv)-kv*kv) * (pixel(2)-muB) * (pixel(2)-muB)/(2*var);
+      }
+      
+      // calculate the squared distance
+      float dist = (HR*HR + HG*HG + HB*HB);
+
+      if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+        bBackgroundHigh = true;
+
+      // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
+      if(dist < m_params.LowThreshold()*var)
+      {
+        bFitsPDF = true;
+
+        // check if this Gaussian is part of the background model
+        if(iModes < backgroundGaussians) 
+          bBackgroundLow = true;
+
+        //update distribution
+        float k = m_params.Alpha() / weight;
+        weight = fOneMinAlpha*weight + m_params.Alpha();
+        m_modes[pos].weight = weight;
+        m_modes[pos].muR = muR - k*(dR);
+        m_modes[pos].muG = muG - k*(dG);
+        m_modes[pos].muB = muB - k*(dB);
+
+        //limit the variance
+        float sigmanew = var + k*(dist-var);
+        m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew;
+        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+      }
+      else
+      {
+        weight = fOneMinAlpha*weight;
+        if(weight < 0.0)
+        {
+          weight=0.0;
+          numModes--;
+        }
+
+        m_modes[pos].weight = weight;
+        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+      }
+    }
+    else
+    {
+      weight = fOneMinAlpha*weight;
+      if(weight < 0.0)
+      {
+        weight=0.0;
+        numModes--;
+      }
+      m_modes[pos].weight = weight;
+      m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+    }
+
+    totalWeight += weight;
+  }
+
+  // renormalize weights so they add to one
+  double invTotalWeight = 1.0 / totalWeight;
+  for(int iLocal = 0; iLocal < numModes; iLocal++)
+  {
+    m_modes[posPixel + iLocal].weight *= (float)invTotalWeight;
+    m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight 
+      / sqrt(m_modes[posPixel + iLocal].variance);
+  }
+
+  // Sort significance values so they are in desending order. 
+  qsort(&m_modes[posPixel],  numModes, sizeof(GMM), compareT2FGMM);
+
+  // make new mode if needed and exit
+  if(!bFitsPDF)
+  {
+    if(numModes < m_params.MaxModes())
+      numModes++;
+    //else
+      // the weakest mode will be replaced
+    
+    pos = posPixel + numModes-1;
+
+    m_modes[pos].muR = pixel.ch[0];
+    m_modes[pos].muG = pixel.ch[1];
+    m_modes[pos].muB = pixel.ch[2];
+    m_modes[pos].variance = m_variance;
+    m_modes[pos].significants = 0;			// will be set below
+
+    if (numModes == 1)
+      m_modes[pos].weight = 1;
+    else
+      m_modes[pos].weight = m_params.Alpha();
+
+    //renormalize weights
+    int iLocal;
+    float sum = 0.0;
+    for(iLocal = 0; iLocal < numModes; iLocal++)
+      sum += m_modes[posPixel+ iLocal].weight;
+    
+    double invSum = 1.0/sum;
+    for(iLocal = 0; iLocal < numModes; iLocal++)
+    {
+      m_modes[posPixel + iLocal].weight *= (float)invSum;
+      m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance);
+    }
+  }
+
+  // Sort significance values so they are in desending order. 
+  qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareT2FGMM);
+
+  if(bBackgroundLow)
+    low_threshold = BACKGROUND;
+  else
+    low_threshold = FOREGROUND;
+  
+  if(bBackgroundHigh)
+    high_threshold = BACKGROUND;
+  else
+    high_threshold = FOREGROUND;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					(the memory should already be reserved) 
+//					values: 255-foreground, 125-shadow, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void T2FGMM::Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+  unsigned char low_threshold, high_threshold;
+  long posPixel;
+
+  // update each pixel of the image
+  for(unsigned int r = 0; r < m_params.Height(); ++r)
+  {
+    for(unsigned int c = 0; c < m_params.Width(); ++c)
+    {		
+      // update model + background subtract
+      posPixel = (r*m_params.Width() + c) * m_params.MaxModes();
+
+      SubtractPixel(posPixel, data(r,c), m_modes_per_pixel(r,c), low_threshold, high_threshold);
+
+      low_threshold_mask(r,c) = low_threshold;
+      high_threshold_mask(r,c) = high_threshold;
+
+      m_background(r,c,0) = (unsigned char) m_modes[posPixel].muR;
+      m_background(r,c,1) = (unsigned char) m_modes[posPixel].muG;
+      m_background(r,c,2) = (unsigned char) m_modes[posPixel].muB;
+    }
+  }
+}
diff --git a/package_bgs/tb/T2FGMM.h b/package_bgs/tb/T2FGMM.h
new file mode 100644
index 0000000000000000000000000000000000000000..a698e5a821b454c0e9d8def8aea344037cbf88dd
--- /dev/null
+++ b/package_bgs/tb/T2FGMM.h
@@ -0,0 +1,135 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* T2FGMM.h
+*
+* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) 
+* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models"
+* Author: Fida El Baf, Thierry Bouwmans, September 2008
+*
+* This code is based on code by Z. Zivkovic's written for his enhanced GMM
+* background subtraction algorithm: 
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+******************************************************************************/
+
+#ifndef T2F_GMM_
+#define T2F_GMM_
+
+#include "../dp/Bgs.h"
+#include "../dp/GrimsonGMM.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    const int TYPE_T2FGMM_UM = 0;
+    const int TYPE_T2FGMM_UV = 1;
+
+    // --- User adjustable parameters used by the T2F GMM BGS algorithm ---
+    class T2FGMMParams : public BgsParams
+    {
+    public:
+      float &LowThreshold() { return m_low_threshold; }
+      float &HighThreshold() { return m_high_threshold; }
+
+      float &Alpha() { return m_alpha; }
+      int &MaxModes() { return m_max_modes; }
+      int &Type() { return m_type; }
+      float &KM() { return m_km; }
+      float &KV() { return m_kv; }
+
+    private:
+      // Threshold on the squared dist. to decide when a sample is close to an existing 
+      // components. If it is not close to any a new component will be generated. 
+      // Smaller threshold values lead to more generated components and higher threshold values 
+      // lead to a small number of components but they can grow too large.
+      //
+      // It is usual easiest to think of these thresholds as being the number of variances away
+      // from the mean of a pixel before it is considered to be from the foreground.
+      float m_low_threshold;
+      float m_high_threshold;
+
+      // alpha - speed of update - if the time interval you want to average over is T
+      // set alpha=1/T. 
+      float m_alpha;
+
+      // Maximum number of modes (Gaussian components) that will be used per pixel
+      int m_max_modes;
+
+      // T2FGMM_UM / T2FGMM_UV
+      int m_type;
+
+      // Factor control for the T2FGMM-UM
+      float m_km;
+
+      // Factor control for the T2FGMM-UV
+      float m_kv;
+    };
+
+    // --- T2FGMM BGS algorithm ---
+    class T2FGMM : public Bgs
+    {
+    public:
+      T2FGMM();
+      ~T2FGMM();
+
+      void Initalize(const BgsParams& param);
+
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data, const BwImage& update_mask);
+
+      RgbImage* Background();
+
+    private:	
+      void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold);
+
+      // User adjustable parameters
+      T2FGMMParams m_params;
+
+      // Threshold when the component becomes significant enough to be included into
+      // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
+      // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+      // it is considered foreground
+      float m_bg_threshold; //1-cf from the paper
+
+      // Initial variance for the newly generated components. 
+      // It will will influence the speed of adaptation. A good guess should be made. 
+      // A simple way is to estimate the typical standard deviation from the images.
+      float m_variance;
+
+      // Dynamic array for the mixture of Gaussians
+      GMM* m_modes;
+
+      // Number of Gaussian components per pixel
+      BwImage m_modes_per_pixel;
+
+      // Current background model
+      RgbImage m_background;
+
+      // Factor control for the T2FGMM-UM
+      float km;
+
+      // Factor control for the T2FGMM-UV
+      float kv;
+    };
+  };
+};
+
+#endif
diff --git a/package_bgs/tb/T2FGMM_UM.cpp b/package_bgs/tb/T2FGMM_UM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aaf280f3cac0f78661cceb6479162b4af0643fb3
--- /dev/null
+++ b/package_bgs/tb/T2FGMM_UM.cpp
@@ -0,0 +1,111 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "T2FGMM_UM.h"
+
+T2FGMM_UM::T2FGMM_UM() : firstTime(true), frameNumber(0), showOutput(true), threshold(9.0), alpha(0.01), gaussians(3), km(1.5), kv(0.6)
+{
+  std::cout << "T2FGMM_UM()" << std::endl;
+}
+
+T2FGMM_UM::~T2FGMM_UM()
+{
+  std::cout << "~T2FGMM_UM()" << std::endl;
+}
+
+void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold;
+    params.HighThreshold() = 2*params.LowThreshold();
+    params.Alpha() = alpha;
+    params.MaxModes() = gaussians;
+    params.Type() = TYPE_T2FGMM_UM;
+    params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5
+    params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("T2FGMM-UM", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void T2FGMM_UM::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UM.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteReal(fs, "km", km);
+  cvWriteReal(fs, "kv", kv);
+  cvWriteInt(fs, "gaussians", gaussians);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void T2FGMM_UM::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UM.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 9.0);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.01);
+  km = cvReadRealByName(fs, 0, "km", 1.5);
+  kv = cvReadRealByName(fs, 0, "kv", 0.6);
+  gaussians = cvReadIntByName(fs, 0, "gaussians", 3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/tb/T2FGMM_UM.h b/package_bgs/tb/T2FGMM_UM.h
new file mode 100644
index 0000000000000000000000000000000000000000..17e06c58877333d06f3bc5bc779641819eea7aa2
--- /dev/null
+++ b/package_bgs/tb/T2FGMM_UM.h
@@ -0,0 +1,58 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "T2FGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class T2FGMM_UM : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  T2FGMMParams params;
+  T2FGMM bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  float km;
+  float kv;
+  int gaussians;
+  bool showOutput;
+
+public:
+  T2FGMM_UM();
+  ~T2FGMM_UM();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/tb/T2FGMM_UV.cpp b/package_bgs/tb/T2FGMM_UV.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6094fe30d9dce9d74672bf44b4d80384e56b1bfd
--- /dev/null
+++ b/package_bgs/tb/T2FGMM_UV.cpp
@@ -0,0 +1,111 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "T2FGMM_UV.h"
+
+T2FGMM_UV::T2FGMM_UV() : firstTime(true), frameNumber(0), showOutput(true), threshold(9.0), alpha(0.01), gaussians(3), km(1.5), kv(0.6)
+{
+  std::cout << "T2FGMM_UV()" << std::endl;
+}
+
+T2FGMM_UV::~T2FGMM_UV()
+{
+  std::cout << "~T2FGMM_UV()" << std::endl;
+}
+
+void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold;
+    params.HighThreshold() = 2*params.LowThreshold();
+    params.Alpha() = alpha;
+    params.MaxModes() = gaussians;
+    params.Type() = TYPE_T2FGMM_UV;
+    params.KM() = km; // Factor control for the T2FGMM-UM [0,3] default: 1.5
+    params.KV() = kv; // Factor control for the T2FGMM-UV [0.3,1] default: 0.6
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("T2FGMM-UV", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  firstTime = false;
+  frameNumber++;
+}
+
+void T2FGMM_UV::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UV.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteReal(fs, "km", km);
+  cvWriteReal(fs, "kv", kv);
+  cvWriteInt(fs, "gaussians", gaussians);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void T2FGMM_UV::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UV.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 9.0);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.01);
+  km = cvReadRealByName(fs, 0, "km", 1.5);
+  kv = cvReadRealByName(fs, 0, "kv", 0.6);
+  gaussians = cvReadIntByName(fs, 0, "gaussians", 3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
\ No newline at end of file
diff --git a/package_bgs/tb/T2FGMM_UV.h b/package_bgs/tb/T2FGMM_UV.h
new file mode 100644
index 0000000000000000000000000000000000000000..23c0bf1a4bfbbe88913d4808aaabdbdfc742f4b8
--- /dev/null
+++ b/package_bgs/tb/T2FGMM_UV.h
@@ -0,0 +1,58 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "T2FGMM.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class T2FGMM_UV : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage* frame;
+  RgbImage frame_data;
+
+  T2FGMMParams params;
+  T2FGMM bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  float km;
+  float kv;
+  int gaussians;
+  bool showOutput;
+
+public:
+  T2FGMM_UV();
+  ~T2FGMM_UV();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
+
diff --git a/package_bgs/tb/T2FMRF.cpp b/package_bgs/tb/T2FMRF.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3d486bb79c8f2b73ef40339308f5db007ae3973c
--- /dev/null
+++ b/package_bgs/tb/T2FMRF.cpp
@@ -0,0 +1,432 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* T2FMRF.cpp
+*
+* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) 
+* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models"
+* Author: Fida El Baf, Thierry Bouwmans, September 2008
+*
+* This code is based on code by Z. Zivkovic's written for his enhanced GMM
+* background subtraction algorithm: 
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+******************************************************************************/
+
+#include "T2FMRF.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+int compareT2FMRF(const void* _gmm1, const void* _gmm2)
+{
+  GMM gmm1 = *(GMM*)_gmm1;
+  GMM gmm2 = *(GMM*)_gmm2;
+
+  if(gmm1.significants < gmm2.significants)
+    return 1;
+  else if(gmm1.significants == gmm2.significants)
+    return 0;
+  else
+    return -1;
+}
+
+GMM* T2FMRF::gmm()
+{
+  return m_modes;
+}
+HMM* T2FMRF::hmm()
+{
+  return m_state;
+}
+
+T2FMRF::T2FMRF()
+{
+  m_modes = NULL;
+}
+
+T2FMRF::~T2FMRF()
+{
+  if(m_modes != NULL) 
+    delete[] m_modes;
+}
+
+void T2FMRF::Initalize(const BgsParams& param)
+{
+  m_params = (T2FMRFParams&) param;
+
+  // Tbf - the threshold
+  m_bg_threshold = 0.75f;	// 1-cf from the paper 
+
+  // Tgenerate - the threshold
+  m_variance = 36.0f;		// sigma for the new mode
+
+  // GMM for each pixel
+  m_modes = new GMM[m_params.Size()*m_params.MaxModes()];
+
+  //HMM for each pixel
+  m_state = new HMM[m_params.Size()];
+
+  // used modes per pixel
+  m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1);
+
+  m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3);
+
+  // Factor control for the T2FGMM-UM [0,3]
+  // km = (float) 2; //1.5;
+  km = (float) m_params.KM();
+
+  // Factor control for the T2FGMM-UV [0.3,1]
+  // kv = (float) 0.9; //0.6;
+  kv = (float) m_params.KV();
+}
+
+RgbImage* T2FMRF::Background()
+{
+  return &m_background;
+}
+
+void T2FMRF::InitModel(const RgbImage& data)
+{
+  m_modes_per_pixel.Clear();
+
+  for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i)
+  {
+    m_modes[i].weight = 0;
+    m_modes[i].variance = 0;
+    m_modes[i].muR = 0;
+    m_modes[i].muG = 0;
+    m_modes[i].muB = 0;
+    m_modes[i].significants = 0;
+  }
+
+  for (unsigned int j = 0; j < m_params.Size(); ++j)
+  {
+    m_state[j].State = background;
+    m_state[j].Ab2b = 0.7;
+    m_state[j].Ab2f = 0.3;
+    m_state[j].Af2b = 0.4;
+    m_state[j].Af2f = 0.6;
+    m_state[j].T = 0.7;
+  }
+}
+
+void T2FMRF::Update(int frame_num, const RgbImage& data,  const BwImage& update_mask)
+{
+  // it doesn't make sense to have conditional updates in the GMM framework
+}
+
+void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, 
+                           unsigned char& low_threshold, unsigned char& high_threshold)
+{
+  // calculate distances to the modes (+ sort???)
+  // here we need to go in descending order!!!
+  long pos;
+  bool bFitsPDF = false;
+  bool bBackgroundLow = false;
+  bool bBackgroundHigh = false;
+
+  HiddenState CurrentState = m_state[posPixel].State;
+  float Ab2b = m_state[posPixel].Ab2b;
+  float Ab2f = m_state[posPixel].Ab2f;
+  float Af2b = m_state[posPixel].Af2b;
+  float Af2f = m_state[posPixel].Af2f;
+  float T = m_state[posPixel].T;
+
+  float fOneMinAlpha = 1 - m_params.Alpha();
+  float totalWeight = 0.0f;
+
+  // calculate number of Gaussians to include in the background model
+  int backgroundGaussians = 0;
+  double sum = 0.0;
+  for(int i = 0; i < numModes; ++i)
+  {
+    if(sum < m_bg_threshold)
+    {
+      backgroundGaussians++;
+      sum += m_modes[posGMode+i].weight;
+    }
+    else
+      break;
+  }
+
+  // update all distributions and check for match with current pixel
+  for (int iModes = 0; iModes < numModes; iModes++)
+  {
+    pos = posGMode + iModes;
+    float weight = m_modes[pos].weight;
+
+    // fit not found yet
+    if (!bFitsPDF)
+    {
+      //check if it belongs to some of the modes
+      //calculate distance
+      float var = m_modes[pos].variance;
+      float muR = m_modes[pos].muR;
+      float muG = m_modes[pos].muG;
+      float muB = m_modes[pos].muB;
+
+      //float km = 2;
+      //float kv = 0.9;
+
+      float dR = fabs(muR - pixel(0));
+      float dG = fabs(muG - pixel(1));
+      float dB = fabs(muB - pixel(2));
+
+      // calculate the squared distance
+      float HR;
+      float HG;
+      float HB;
+
+      // T2FMRF-UM
+      if(m_params.Type() == TYPE_T2FMRF_UM)
+      {
+        if((pixel(0) < muR-km*var) || (pixel(0) > muR+km*var))
+          HR = 2*km*dR/var;
+        else
+          HR = dR*dR/(2*var*var)+km*dR/var+km*km/2;
+
+        if((pixel(1) < muG-km*var) || (pixel(1) > muG+km*var))
+          HG = 2*km*dG/var;
+        else
+          HG = dG*dG/(2*var*var)+km*dG/var+km*km/2;
+
+        if((pixel(2) < muB-km*var) || (pixel(2) > muB+km*var))
+          HB = 2*km*dB/var;
+        else
+          HB = dB*dB/(2*var*var)+km*dB/var+km*km/2;
+      }
+
+      // T2FGMM-UV
+      if(m_params.Type() == TYPE_T2FMRF_UV)
+      {
+        HR = (1/(kv*kv)-kv*kv) * (pixel(0)-muR) * (pixel(0)-muR)/(2*var);
+        HG = (1/(kv*kv)-kv*kv) * (pixel(1)-muG) * (pixel(1)-muG)/(2*var);
+        HB = (1/(kv*kv)-kv*kv) * (pixel(2)-muB) * (pixel(2)-muB)/(2*var);
+      }
+
+      float ro;
+      if (CurrentState == background)
+      {
+        if (Ab2b!=0) ro = (Ab2f/Ab2b);
+        else ro = 10;
+      }
+      else
+      {
+        if(Af2b!=0) ro = (Af2f/Af2b);
+        else ro = 10;
+      }
+      
+      // calculate the squared distance
+      float dist = (HR*HR + HG*HG + HB*HB);
+
+      if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians)
+        bBackgroundHigh = true;
+
+      // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution
+      if(dist < m_params.LowThreshold()*var)
+      {
+        bFitsPDF = true;
+
+        // check if this Gaussian is part of the background model
+        if(iModes < backgroundGaussians) 
+          bBackgroundLow = true;
+
+        //update distribution
+        float k = m_params.Alpha() / weight;
+        weight = fOneMinAlpha*weight + m_params.Alpha();
+        m_modes[pos].weight = weight;
+        m_modes[pos].muR = muR - k*(dR);
+        m_modes[pos].muG = muG - k*(dG);
+        m_modes[pos].muB = muB - k*(dB);
+
+        //limit the variance
+        float sigmanew = var + k*(dist-var);
+        m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew;
+        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+      }
+      else
+      {
+        weight = fOneMinAlpha*weight;
+        if (weight < 0.0)
+        {
+          weight=0.0;
+          numModes--;
+        }
+
+        m_modes[pos].weight = weight;
+        m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+      }
+    }
+    else
+    {
+      weight = fOneMinAlpha*weight;
+      if (weight < 0.0)
+      {
+        weight=0.0;
+        numModes--;
+      }
+      m_modes[pos].weight = weight;
+      m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance);
+    }
+
+    totalWeight += weight;
+  }
+
+  // renormalize weights so they add to one
+  double invTotalWeight = 1.0 / totalWeight;
+  for (int iLocal = 0; iLocal < numModes; iLocal++)
+  {
+    m_modes[posGMode + iLocal].weight *= (float)invTotalWeight;
+    m_modes[posGMode + iLocal].significants = m_modes[posGMode + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance);
+  }
+
+  // Sort significance values so they are in desending order. 
+  qsort(&m_modes[posGMode],  numModes, sizeof(GMM), compareT2FMRF);
+
+  // make new mode if needed and exit
+  if(!bFitsPDF)
+  {
+    if(numModes < m_params.MaxModes())
+      numModes++;
+    //else
+      // the weakest mode will be replaced
+    
+    pos = posGMode + numModes-1;
+
+    m_modes[pos].muR = pixel.ch[0];
+    m_modes[pos].muG = pixel.ch[1];
+    m_modes[pos].muB = pixel.ch[2];
+    m_modes[pos].variance = m_variance;
+    m_modes[pos].significants = 0;			// will be set below
+
+    if(numModes == 1)
+      m_modes[pos].weight = 1;
+    else
+      m_modes[pos].weight = m_params.Alpha();
+
+    //renormalize weights
+    int iLocal;
+    float sum = 0.0;
+    for(iLocal = 0; iLocal < numModes; iLocal++)
+      sum += m_modes[posGMode+ iLocal].weight;
+    
+    double invSum = 1.0/sum;
+    for(iLocal = 0; iLocal < numModes; iLocal++)
+    {
+      m_modes[posGMode + iLocal].weight *= (float)invSum;
+      m_modes[posGMode + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance);
+    }
+  }
+
+  // Sort significance values so they are in desending order. 
+  qsort(&(m_modes[posGMode]), numModes, sizeof(GMM), compareT2FMRF);
+
+  if(bBackgroundLow)
+  {
+    low_threshold = BACKGROUND;
+    m_state[posPixel].State = background;
+
+    if(CurrentState == background)
+    {
+      float b2b = fOneMinAlpha*Ab2b + m_params.Alpha();
+      float b2f = fOneMinAlpha*Ab2f;
+
+      float b = b2b + b2f;
+      m_state[posPixel].Ab2b = b2b/b;
+      m_state[posPixel].Ab2f = b2f/b;
+      m_state[posPixel].T = m_state[posPixel].Ab2b;
+    }
+    else
+    {
+      float f2b = fOneMinAlpha*Af2b + m_params.Alpha();
+      float f2f = fOneMinAlpha*Af2f;
+
+      float f = f2b + f2f;
+      m_state[posPixel].Af2b = f2b/f;
+      m_state[posPixel].Af2f = f2f/f;
+      m_state[posPixel].T = m_state[posPixel].Af2b;
+    }
+  }
+  else
+  {
+    low_threshold = FOREGROUND;
+    m_state[posPixel].State = foreground;
+
+    if(CurrentState == background)
+    {
+      float b2b = fOneMinAlpha*Ab2b;
+      float b2f = fOneMinAlpha*Ab2f + m_params.Alpha();
+
+      float b = b2b + b2f;
+      m_state[posPixel].Ab2b = b2b/b;
+      m_state[posPixel].Ab2f = b2f/b;
+      m_state[posPixel].T = m_state[posPixel].Ab2b;
+    }
+    else
+    {
+      float f2b = fOneMinAlpha*Af2b;
+      float f2f = fOneMinAlpha*Af2f + m_params.Alpha();
+
+      float f = f2b + f2f;
+      m_state[posPixel].Af2b = f2b/f;
+      m_state[posPixel].Af2f = f2f/f;
+      m_state[posPixel].T = m_state[posPixel].Af2b;
+    }
+  }
+
+  if(bBackgroundHigh)
+    high_threshold = BACKGROUND;
+  else
+    high_threshold = FOREGROUND;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//Input:
+//  data - a pointer to the data of a RGB image of the same size
+//Output:
+//  output - a pointer to the data of a gray value image of the same size 
+//					(the memory should already be reserved) 
+//					values: 255-foreground, 125-shadow, 0-background
+///////////////////////////////////////////////////////////////////////////////
+void T2FMRF::Subtract(int frame_num, const RgbImage& data,  
+                      BwImage& low_threshold_mask, BwImage& high_threshold_mask)
+{
+  unsigned char low_threshold, high_threshold;
+  long posPixel;
+  long posGMode;
+
+  // update each pixel of the image
+  for(unsigned int r = 0; r < m_params.Height(); ++r)
+  {
+    for(unsigned int c = 0; c < m_params.Width(); ++c)
+    {		
+      // update model + background subtract
+      posPixel = r*m_params.Width() + c;
+      posGMode = (r*m_params.Width() + c) * m_params.MaxModes();
+
+      SubtractPixel(posPixel, posGMode, data(r,c), m_modes_per_pixel(r,c), low_threshold, high_threshold);
+
+      low_threshold_mask(r,c) = low_threshold;
+      high_threshold_mask(r,c) = high_threshold;
+
+      m_background(r,c,0) = (unsigned char) m_modes[posGMode].muR;
+      m_background(r,c,1) = (unsigned char) m_modes[posGMode].muG;
+      m_background(r,c,2) = (unsigned char) m_modes[posGMode].muB;
+    }
+  }
+}
diff --git a/package_bgs/tb/T2FMRF.h b/package_bgs/tb/T2FMRF.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6fb4495638622431c2345a44ce0fd6bc485a595
--- /dev/null
+++ b/package_bgs/tb/T2FMRF.h
@@ -0,0 +1,164 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/****************************************************************************
+*
+* T2FMRF.h
+*
+* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) 
+* "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models"
+* Author: Fida El Baf, Thierry Bouwmans, September 2008
+*
+* This code is based on code by Z. Zivkovic's written for his enhanced GMM
+* background subtraction algorithm: 
+*
+* Zivkovic's code can be obtained at: www.zoranz.net
+******************************************************************************/
+
+#ifndef T2F_MRF_
+#define T2F_MRF_
+
+#include "../dp/Bgs.h"
+#include "../dp/GrimsonGMM.h"
+
+namespace Algorithms
+{
+  namespace BackgroundSubtraction
+  {
+    const int TYPE_T2FMRF_UM = 0;
+    const int TYPE_T2FMRF_UV = 1;
+
+    enum HiddenState {background, foreground};
+
+    typedef struct HMMState 
+    {
+      float T;
+      //Hidden State
+      HiddenState State;
+      //transition probability
+      float Ab2b;
+      float Ab2f;
+      float Af2f;
+      float Af2b;
+    } HMM;
+
+    //typedef struct GMMGaussian
+    //{
+    //  float variance;
+    //  float muR;
+    //  float muG;
+    //  float muB;
+    //  float weight;
+    //  float significants; // this is equal to weight / standard deviation and is used to
+    //  // determine which Gaussians should be part of the background model
+    //} GMM;
+
+    // --- User adjustable parameters used by the T2F GMM BGS algorithm ---
+    class T2FMRFParams : public BgsParams
+    {
+    public:
+      float &LowThreshold() { return m_low_threshold; }
+      float &HighThreshold() { return m_high_threshold; }
+
+      float &Alpha() { return m_alpha; }
+      int &MaxModes() { return m_max_modes; }
+      int &Type() { return m_type; }
+      float &KM() { return m_km; }
+      float &KV() { return m_kv; }
+
+    private:
+      // Threshold on the squared dist. to decide when a sample is close to an existing 
+      // components. If it is not close to any a new component will be generated. 
+      // Smaller threshold values lead to more generated components and higher threshold values 
+      // lead to a small number of components but they can grow too large.
+      //
+      // It is usual easiest to think of these thresholds as being the number of variances away
+      // from the mean of a pixel before it is considered to be from the foreground.
+      float m_low_threshold;
+      float m_high_threshold;
+
+      // alpha - speed of update - if the time interval you want to average over is T
+      // set alpha=1/T. 
+      float m_alpha;
+
+      // Maximum number of modes (Gaussian components) that will be used per pixel
+      int m_max_modes;
+
+      // T2FMRF_UM / T2FMRF_UV
+      int m_type;
+
+      // Factor control for the T2FMRF-UM
+      float m_km;
+
+      // Factor control for the T2FMRF-UV
+      float m_kv;
+    };
+
+    // --- T2FGMM BGS algorithm ---
+    class T2FMRF : public Bgs
+    {
+    public:
+      T2FMRF();
+      ~T2FMRF();
+
+      void Initalize(const BgsParams& param);
+      void InitModel(const RgbImage& data);
+      void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask);	
+      void Update(int frame_num, const RgbImage& data, const BwImage& update_mask);
+
+      RgbImage* Background();
+
+      GMM *gmm(void);
+      HMM *hmm(void);
+
+    private:	
+      void SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold);
+
+      // User adjustable parameters
+      T2FMRFParams m_params;
+
+      // Threshold when the component becomes significant enough to be included into
+      // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9
+      // For alpha=0.001 it means that the mode should exist for approximately 105 frames before
+      // it is considered foreground
+      float m_bg_threshold; //1-cf from the paper
+
+      // Initial variance for the newly generated components. 
+      // It will will influence the speed of adaptation. A good guess should be made. 
+      // A simple way is to estimate the typical standard deviation from the images.
+      float m_variance;
+
+      // Dynamic array for the mixture of Gaussians
+      GMM* m_modes;
+
+      //Dynamic array for the hidden state
+      HMM* m_state;
+
+      // Number of Gaussian components per pixel
+      BwImage m_modes_per_pixel;
+
+      // Current background model
+      RgbImage m_background;
+
+      // Factor control for the T2FGMM-UM
+      float km;
+      // Factor control for the T2FGMM-UV
+      float kv;
+    };
+  };
+};
+
+#endif
diff --git a/package_bgs/tb/T2FMRF_UM.cpp b/package_bgs/tb/T2FMRF_UM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..768db3931902d908664045c30ea46ff86838e504
--- /dev/null
+++ b/package_bgs/tb/T2FMRF_UM.cpp
@@ -0,0 +1,140 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "T2FMRF_UM.h"
+
+T2FMRF_UM::T2FMRF_UM() : firstTime(true), frameNumber(0), showOutput(true), threshold(9.0), alpha(0.01), 
+gaussians(3), km(2), kv(0.9)
+{
+  std::cout << "T2FMRF_UM()" << std::endl;
+}
+
+T2FMRF_UM::~T2FMRF_UM()
+{
+  std::cout << "~T2FMRF_UM()" << std::endl;
+}
+
+void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold;
+    params.HighThreshold() = 2*params.LowThreshold();
+    params.Alpha() = alpha;
+    params.MaxModes() = gaussians;
+    params.Type() = TYPE_T2FMRF_UM;
+    params.KM() = km; // Factor control for the T2FMRF-UM [0,3] default: 2
+    params.KV() = kv; // Factor control for the T2FMRF-UV [0.3,1] default: 0.9
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+
+    old_labeling = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    old = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+
+    mrf.height = height;
+	  mrf.width = width;
+    mrf.Build_Classes_OldLabeling_InImage_LocalEnergy();
+
+    firstTime = false;
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  cvCopyImage(lowThresholdMask.Ptr(), old);
+
+  /************************************************************************/
+	/* the code for MRF, it can be noted when using other methods   */
+	/************************************************************************/
+	//the optimization process is done when the foreground detection is stable, 
+	if(frameNumber >= 10)
+	{
+		gmm = bgs.gmm();
+		hmm = bgs.hmm();
+		mrf.background2 = frame_data.Ptr();
+		mrf.in_image = lowThresholdMask.Ptr();
+		mrf.out_image = lowThresholdMask.Ptr();
+		mrf.InitEvidence2(gmm,hmm,old_labeling);
+		mrf.ICM2();
+		cvCopyImage(mrf.out_image, lowThresholdMask.Ptr());
+	}
+
+  cvCopyImage(old, old_labeling);
+
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("T2FMRF-UM", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  frameNumber++;
+}
+
+void T2FMRF_UM::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UM.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteReal(fs, "km", km);
+  cvWriteReal(fs, "kv", kv);
+  cvWriteInt(fs, "gaussians", gaussians);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void T2FMRF_UM::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UM.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 9.0);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.01);
+  km = cvReadRealByName(fs, 0, "km", 2);
+  kv = cvReadRealByName(fs, 0, "kv", 0.9);
+  gaussians = cvReadIntByName(fs, 0, "gaussians", 3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/tb/T2FMRF_UM.h b/package_bgs/tb/T2FMRF_UM.h
new file mode 100644
index 0000000000000000000000000000000000000000..6066834957460f6a787a1672f68332eee010d06e
--- /dev/null
+++ b/package_bgs/tb/T2FMRF_UM.h
@@ -0,0 +1,64 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "MRF.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class T2FMRF_UM : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage *frame;
+  RgbImage frame_data;
+
+  IplImage *old_labeling;
+  IplImage *old;
+
+  T2FMRFParams params;
+  T2FMRF bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  float km;
+  float kv;
+  int gaussians;
+  bool showOutput;
+
+  MRF_TC mrf;
+  GMM *gmm;
+  HMM *hmm;
+
+public:
+  T2FMRF_UM();
+  ~T2FMRF_UM();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/package_bgs/tb/T2FMRF_UV.cpp b/package_bgs/tb/T2FMRF_UV.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b6fcc012e719097fed353638862a034d7ccdb9c
--- /dev/null
+++ b/package_bgs/tb/T2FMRF_UV.cpp
@@ -0,0 +1,140 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "T2FMRF_UV.h"
+
+T2FMRF_UV::T2FMRF_UV() : firstTime(true), frameNumber(0), showOutput(true), threshold(9.0), alpha(0.01), 
+gaussians(3), km(2), kv(0.9)
+{
+  std::cout << "T2FMRF_UV()" << std::endl;
+}
+
+T2FMRF_UV::~T2FMRF_UV()
+{
+  std::cout << "~T2FMRF_UV()" << std::endl;
+}
+
+void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel)
+{
+  if(img_input.empty())
+    return;
+
+  loadConfig();
+
+  if(firstTime)
+    saveConfig();
+
+  frame = new IplImage(img_input);
+  
+  if(firstTime)
+    frame_data.ReleaseMemory(false);
+  frame_data = frame;
+
+  if(firstTime)
+  {
+    int width	= img_input.size().width;
+    int height = img_input.size().height;
+
+    lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL;
+
+    params.SetFrameSize(width, height);
+    params.LowThreshold() = threshold;
+    params.HighThreshold() = 2*params.LowThreshold();
+    params.Alpha() = alpha;
+    params.MaxModes() = gaussians;
+    params.Type() = TYPE_T2FMRF_UV;
+    params.KM() = km; // Factor control for the T2FMRF-UM [0,3] default: 2
+    params.KV() = kv; // Factor control for the T2FMRF-UV [0.3,1] default: 0.9
+
+    bgs.Initalize(params);
+    bgs.InitModel(frame_data);
+
+    old_labeling = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+    old = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
+
+    mrf.height = height;
+	  mrf.width = width;
+    mrf.Build_Classes_OldLabeling_InImage_LocalEnergy();
+
+    firstTime = false;
+  }
+
+  bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask);
+  cvCopyImage(lowThresholdMask.Ptr(), old);
+
+  /************************************************************************/
+	/* the code for MRF, it can be noted when using other methods   */
+	/************************************************************************/
+	//the optimization process is done when the foreground detection is stable, 
+	if(frameNumber >= 10)
+	{
+		gmm = bgs.gmm();
+		hmm = bgs.hmm();
+		mrf.background2 = frame_data.Ptr();
+		mrf.in_image = lowThresholdMask.Ptr();
+		mrf.out_image = lowThresholdMask.Ptr();
+		mrf.InitEvidence2(gmm,hmm,old_labeling);
+		mrf.ICM2();
+		cvCopyImage(mrf.out_image, lowThresholdMask.Ptr());
+	}
+
+  cvCopyImage(old, old_labeling);
+
+  lowThresholdMask.Clear();
+  bgs.Update(frameNumber, frame_data, lowThresholdMask);
+  
+  cv::Mat foreground(highThresholdMask.Ptr());
+
+  if(showOutput)
+    cv::imshow("T2FMRF-UV", foreground);
+  
+  foreground.copyTo(img_output);
+
+  delete frame;
+  frameNumber++;
+}
+
+void T2FMRF_UV::saveConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UV.xml", 0, CV_STORAGE_WRITE);
+
+  cvWriteReal(fs, "threshold", threshold);
+  cvWriteReal(fs, "alpha", alpha);
+  cvWriteReal(fs, "km", km);
+  cvWriteReal(fs, "kv", kv);
+  cvWriteInt(fs, "gaussians", gaussians);
+  cvWriteInt(fs, "showOutput", showOutput);
+
+  cvReleaseFileStorage(&fs);
+}
+
+void T2FMRF_UV::loadConfig()
+{
+  CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UV.xml", 0, CV_STORAGE_READ);
+  
+  threshold = cvReadRealByName(fs, 0, "threshold", 9.0);
+  alpha = cvReadRealByName(fs, 0, "alpha", 0.01);
+  km = cvReadRealByName(fs, 0, "km", 2);
+  kv = cvReadRealByName(fs, 0, "kv", 0.9);
+  gaussians = cvReadIntByName(fs, 0, "gaussians", 3);
+  showOutput = cvReadIntByName(fs, 0, "showOutput", true);
+
+  cvReleaseFileStorage(&fs);
+}
diff --git a/package_bgs/tb/T2FMRF_UV.h b/package_bgs/tb/T2FMRF_UV.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8c0ff072a1cba191e6d848faf06a81c12d42db5
--- /dev/null
+++ b/package_bgs/tb/T2FMRF_UV.h
@@ -0,0 +1,64 @@
+/*
+This file is part of BGSLibrary.
+
+BGSLibrary is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+BGSLibrary is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with BGSLibrary.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#pragma once
+
+#include <iostream>
+#include <cv.h>
+#include <highgui.h>
+
+#include "../IBGS.h"
+#include "MRF.h"
+
+using namespace Algorithms::BackgroundSubtraction;
+
+class T2FMRF_UV : public IBGS
+{
+private:
+  bool firstTime;
+  long frameNumber;
+  IplImage *frame;
+  RgbImage frame_data;
+
+  IplImage *old_labeling;
+  IplImage *old;
+
+  T2FMRFParams params;
+  T2FMRF bgs;
+  BwImage lowThresholdMask;
+  BwImage highThresholdMask;
+
+  double threshold;
+  double alpha;
+  float km;
+  float kv;
+  int gaussians;
+  bool showOutput;
+
+  MRF_TC mrf;
+  GMM *gmm;
+  HMM *hmm;
+
+public:
+  T2FMRF_UV();
+  ~T2FMRF_UV();
+
+  void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel);
+
+private:
+  void saveConfig();
+  void loadConfig();
+};
diff --git a/run_camera.sh b/run_camera.sh
new file mode 100644
index 0000000000000000000000000000000000000000..f000519fdbe3b6a6d9c0b38d8a08e55ecdee364b
--- /dev/null
+++ b/run_camera.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+./build/bgs --use_cam --camera=0
+
diff --git a/run_demo.sh b/run_demo.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e734f061f62f56b7d0877bb63bbaa243d2762359
--- /dev/null
+++ b/run_demo.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+./build/bgs_demo dataset/video.avi
+
diff --git a/run_video.sh b/run_video.sh
new file mode 100644
index 0000000000000000000000000000000000000000..0ae1bcb7b9f036e44010800a5133ed6896fbbc42
--- /dev/null
+++ b/run_video.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+./build/bgs -uf -fn=dataset/video.avi
+
diff --git a/vs2010/bgslibrary.sln b/vs2010/bgslibrary.sln
new file mode 100644
index 0000000000000000000000000000000000000000..06187d0549eb46226ede71906d13e14a2d563691
--- /dev/null
+++ b/vs2010/bgslibrary.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bgslibrary", "bgslibrary.vcxproj", "{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Debug|Win32.Build.0 = Debug|Win32
+		{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|Win32.ActiveCfg = Release|Win32
+		{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/vs2010/bgslibrary.suo b/vs2010/bgslibrary.suo
new file mode 100644
index 0000000000000000000000000000000000000000..3dc8e43797f0d1ee8f60b5d84b6328c180a83479
Binary files /dev/null and b/vs2010/bgslibrary.suo differ
diff --git a/vs2010/bgslibrary.vcxproj b/vs2010/bgslibrary.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..5a1b8298ba7f330757e5a77c772c05a6ef22c767
--- /dev/null
+++ b/vs2010/bgslibrary.vcxproj
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>bgslibrary</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>..\</OutDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>C:\OpenCV2.4.5\build\include;C:\OpenCV2.4.5\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>C:\OpenCV2.4.5\build\x86\vc10\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\Demo.cpp" />
+    <ClCompile Include="..\package_analysis\ForegroundMaskAnalysis.cpp" />
+    <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp" />
+    <ClCompile Include="..\package_bgs\ae\KDE.cpp" />
+    <ClCompile Include="..\package_bgs\ae\KernelTable.cpp" />
+    <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp" />
+    <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp" />
+    <ClCompile Include="..\package_bgs\av\TBackground.cpp" />
+    <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp" />
+    <ClCompile Include="..\package_bgs\av\VuMeter.cpp" />
+    <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\Blob.cpp" />
+    <ClCompile Include="..\package_bgs\dp\BlobExtraction.cpp" />
+    <ClCompile Include="..\package_bgs\dp\BlobResult.cpp" />
+    <ClCompile Include="..\package_bgs\dp\ConnectedComponents.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp" />
+    <ClCompile Include="..\package_bgs\dp\Error.cpp" />
+    <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp" />
+    <ClCompile Include="..\package_bgs\dp\Image.cpp" />
+    <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp" />
+    <ClCompile Include="..\package_bgs\dp\WrenGA.cpp" />
+    <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp" />
+    <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp" />
+    <ClCompile Include="..\package_bgs\jmo\blob.cpp" />
+    <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp" />
+    <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp" />
+    <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp" />
+    <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp" />
+    <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp" />
+    <ClCompile Include="..\package_bgs\lb\BGModel.cpp" />
+    <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp" />
+    <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp" />
+    <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp" />
+    <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp" />
+    <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp" />
+    <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp" />
+    <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp" />
+    <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp" />
+    <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp" />
+    <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp" />
+    <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp" />
+    <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp" />
+    <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp" />
+    <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp" />
+    <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp" />
+    <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp" />
+    <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp" />
+    <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp" />
+    <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp" />
+    <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp" />
+    <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp" />
+    <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp" />
+    <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\package_analysis\ForegroundMaskAnalysis.h" />
+    <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h" />
+    <ClInclude Include="..\package_bgs\ae\KDE.h" />
+    <ClInclude Include="..\package_bgs\ae\KernelTable.h" />
+    <ClInclude Include="..\package_bgs\ae\NPBGmodel.h" />
+    <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h" />
+    <ClInclude Include="..\package_bgs\av\TBackground.h" />
+    <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h" />
+    <ClInclude Include="..\package_bgs\av\VuMeter.h" />
+    <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\Bgs.h" />
+    <ClInclude Include="..\package_bgs\dp\BgsParams.h" />
+    <ClInclude Include="..\package_bgs\dp\Blob.h" />
+    <ClInclude Include="..\package_bgs\dp\BlobExtraction.h" />
+    <ClInclude Include="..\package_bgs\dp\BlobResult.h" />
+    <ClInclude Include="..\package_bgs\dp\ConnectedComponents.h" />
+    <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h" />
+    <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\Eigenbackground.h" />
+    <ClInclude Include="..\package_bgs\dp\Error.h" />
+    <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h" />
+    <ClInclude Include="..\package_bgs\dp\Image.h" />
+    <ClInclude Include="..\package_bgs\dp\MeanBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\TextureBGS.h" />
+    <ClInclude Include="..\package_bgs\dp\WrenGA.h" />
+    <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h" />
+    <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h" />
+    <ClInclude Include="..\package_bgs\IBGS.h" />
+    <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h" />
+    <ClInclude Include="..\package_bgs\jmo\BGS.h" />
+    <ClInclude Include="..\package_bgs\jmo\blob.h" />
+    <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h" />
+    <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h" />
+    <ClInclude Include="..\package_bgs\jmo\BlobResult.h" />
+    <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h" />
+    <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h" />
+    <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h" />
+    <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h" />
+    <ClInclude Include="..\package_bgs\lb\BGModel.h" />
+    <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h" />
+    <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h" />
+    <ClInclude Include="..\package_bgs\lb\BGModelGauss.h" />
+    <ClInclude Include="..\package_bgs\lb\BGModelMog.h" />
+    <ClInclude Include="..\package_bgs\lb\BGModelSom.h" />
+    <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h" />
+    <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h" />
+    <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h" />
+    <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h" />
+    <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h" />
+    <ClInclude Include="..\package_bgs\lb\Types.h" />
+    <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h" />
+    <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h" />
+    <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h" />
+    <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h" />
+    <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h" />
+    <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h" />
+    <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h" />
+    <ClInclude Include="..\package_bgs\tb\PixelUtils.h" />
+    <ClInclude Include="..\package_bgs\tb\T2FGMM.h" />
+    <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h" />
+    <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h" />
+    <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h" />
+    <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2010/bgslibrary.vcxproj.filters b/vs2010/bgslibrary.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..7e5b5bb2b4947a8f0b08a91faf990095fcd09936
--- /dev/null
+++ b/vs2010/bgslibrary.vcxproj.filters
@@ -0,0 +1,444 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+    <Filter Include="Header Files\package_analysis">
+      <UniqueIdentifier>{c0cc904e-4bfa-4fd6-ae45-1fe712768308}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs">
+      <UniqueIdentifier>{7d606ab8-5bf7-4ec2-b897-d15eb1de0263}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs\dp">
+      <UniqueIdentifier>{dba27670-a93f-4a25-99e1-948bac19456b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs\jmo">
+      <UniqueIdentifier>{c2f770a4-2284-4a79-a4e3-f4cbf57b3f29}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs\lb">
+      <UniqueIdentifier>{6830e1db-4298-4dae-87c8-615340f28f8f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs\tb">
+      <UniqueIdentifier>{781e472a-2256-437a-ae26-8611653f8882}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs\ae">
+      <UniqueIdentifier>{ec53c3c1-ec12-4d06-a330-dcc626d220f8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\package_bgs\av">
+      <UniqueIdentifier>{5c8f2d51-2d62-4d20-a7bb-b18a28688acd}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\Demo.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_analysis\ForegroundMaskAnalysis.cpp">
+      <Filter>Header Files\package_analysis</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\jmo\blob.cpp">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\BGModel.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\ae\KDE.cpp">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\ae\KernelTable.cpp">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\av\TBackground.cpp">
+      <Filter>Header Files\package_bgs\av</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp">
+      <Filter>Header Files\package_bgs\av</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\av\VuMeter.cpp">
+      <Filter>Header Files\package_bgs\av</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\Blob.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\BlobExtraction.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\BlobResult.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\ConnectedComponents.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\Error.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\Image.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\WrenGA.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\package_analysis\ForegroundMaskAnalysis.h">
+      <Filter>Header Files\package_analysis</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\IBGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h">
+      <Filter>Header Files\package_bgs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\BGS.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\blob.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\BlobResult.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h">
+      <Filter>Header Files\package_bgs\jmo</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\BGModel.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\BGModelGauss.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\BGModelMog.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\BGModelSom.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\lb\Types.h">
+      <Filter>Header Files\package_bgs\lb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\PixelUtils.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\T2FGMM.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h">
+      <Filter>Header Files\package_bgs\tb</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\ae\KDE.h">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\ae\KernelTable.h">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\ae\NPBGmodel.h">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h">
+      <Filter>Header Files\package_bgs\ae</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\av\TBackground.h">
+      <Filter>Header Files\package_bgs\av</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h">
+      <Filter>Header Files\package_bgs\av</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\av\VuMeter.h">
+      <Filter>Header Files\package_bgs\av</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\Bgs.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\BgsParams.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\Blob.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\BlobExtraction.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\BlobResult.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\ConnectedComponents.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\Eigenbackground.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\Error.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\Image.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\MeanBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\TextureBGS.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\WrenGA.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h">
+      <Filter>Header Files\package_bgs\dp</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/vs2010/bgslibrary.vcxproj.user b/vs2010/bgslibrary.vcxproj.user
new file mode 100644
index 0000000000000000000000000000000000000000..2dd78fa19ea4b48204bf74bf752ff5ee1be6887b
--- /dev/null
+++ b/vs2010/bgslibrary.vcxproj.user
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory>
+    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+    <LocalDebuggerCommandArguments>./dataset/video.avi</LocalDebuggerCommandArguments>
+  </PropertyGroup>
+</Project>
\ No newline at end of file