Thursday, February 28, 2019

Tryton News: Newsletter March 2019

@ced wrote:

This month a lot of work has been put on improving and modernize both clients but also on increasing the maintainability of the code.
We also want to remind you that the registration for Tryton Unconference at Marseille, the 4th-7th June is opened. Do not wait too much, the places are limited.

Contents:

Changes For The User

The AEAT303 Spanish report has been updated to follow the new format published this year.

The French chart of account has been updated to include the new accounts 442* from PCG 2019.

Now that the desktop client has dropped the support of GTK+2, we can use new widgets from GTK+3 such as the ShortcutsWindow. This window is displayed with the shortcut CTRL+F1 and provide a search functionality.

Another possibility with GTK+3 was to replace the filter popup window by a nicer Popover. This solved also a focus issue that happened on some window managers.

We changed the shortcut to switch tab to CTRL+Tab for desktop and ALT+Tab for web client. This is more natural for the user.

On the desktop client, we show first the login dialog before the main application window. This has a side effect that it is not possible to know the running version before being connected. As this can lead to some incomprehension if the user is using the wrong version to connect to a server, we display on the login dialog the version number.
Desktop login window with version number

The design of the CSV export/import on the web client was not in the best shape. So we put some effort to redesign it to be closer to the Tryton standard.
Before:


After:

On small screen with the web client, replacing search filter may be difficult. So we added a clear button when the input is filled for such case.

On the search filter popover, some kind of fields (e.g. date) are presented as a range. But to enter a equality clause, the user needs to fill both boundary entries with the exact same value. This is tedious. So we changed the range widget to automatically fill the end boundary with the value of the start boundary when this last is changed. It is still possible to create a range query by modifying the to value.

By default Tryton allows only to sale or purchase products that are marked respectively as salable and purchasable. But it happens that over time, we do no want anymore to sale or purchase a product. The problem is that existing orders may no more be valid because of such change. Now we check the flags only on draft and quotation state of the order and existing orders stay valid.

We have remove the mandatory option on analytic axis because it may break some automatic workflow which created document invalid according to the option. As we have since sometimes now a tool to show account lines for which the analytic axis were not completed.

Sometimes it is useful to be able to see quickly the deposit history of a customer. So we added a new relate link from the party form that displays their non-consumed deposit lines.

A frequent reported issue is that the size of dialogs are often too small on the desktop client. We have implemented a new algorithm that provides a better size by default.

We have improved the spacing of the reference field in the web client. Before this change, it could exceed the cell in an editable list.

Changes For The Developer

To be more compliant with HTTP status, the Tryton server will raise 429 TOO MANY REQUESTS when the login rate reach the limit. This gives also a more comprehensive error message to the user.

A request is retried a number of time if it encounters an database operational error. When such error comes from a lock failure which are performed with NO WAIT, the retries are often too fast for the other request to release the lock. So we have added an increasing delay between the retries.

In the last release, we added a Bus to the server which does long polling with the clients. But our main server is based on thread/fork. With big number of users, it can be very resource consuming to keep a thread for each long polling request. So we added an option to run the server using coroutine.
So now, the typical setup for performance is to run a thread/fork server and activate in the configuration the redirection of the bus requests to another Tryton server running with coroutine.

Until now the developer mode of the server (which activate the auto-reload on file changes) activated the debug level of the logging. It was considered annoying so we decoupled the log level from the developer mode. To increase the logging level, you just have to add more -v to the command line (or use a logging configuration).

The Model.fields_get method was a big function with all sort of tests per field type. It was not modular as the fields were hard-coded and it was difficult to maintain. We split the function between each fields which are now responsible of their own definition.
This allowed to provide the dimension and the geometry type for the Tryton GIS backend.

We added the missing support for width and height of the notebook on the web client.

We have modernized the Javascript of the web client and now we use getters and setters. This makes the Javascript code looks closer to the Python code from the desktop client.

We added the support of the window tab in the URL of the clients. This way they do not disappear when the page is reloaded and when the URL is shared.

Posts: 1

Participants: 1

Read full topic



from Planet Python
via read more

Toshio Kuratomi: Managing vim8 plugins

Vim-8.x gained native plugin handling so that plugin managers like Pathogen and Vundle aren’t needed anymore. Enabling a plugin is as easy as cloning a git repository into the right directory (or unzipping a tarball or making the proper directories or….)

There’s a couple things that aren’t totally convenient, though. vim needs to have a command run to index the help files in a plugin otherwise vim’s :help command won’t be able to find it. And vim doesn’t know anything about how to update the plugins later. So I whipped up a quick script to do both of those things. It’s nothing special but gets the job done: vim-update-plugins.py



from Planet Python
via read more

Blosc joins NumFOCUS Sponsored Projects

The post Blosc joins NumFOCUS Sponsored Projects appeared first on NumFOCUS.



from Planet SciPy
read more

Gina Helfrich on the Changelog Podcast

The post Gina Helfrich on the Changelog Podcast appeared first on NumFOCUS.



from Planet SciPy
read more

Test and Code: 67: Teaching Python in Middle School

In today's episode we talk with Kelly Paredes & Sean Tibor.
They teach Python in a middle school in Florida, and talk about this experience on the podcast Teaching Python.

I love that they include physical computing right from the start, and everything else they are doing.

It's a fun interview.

Special Guests: Kelly Paredes and Sean Tibor.

Sponsored By:

Support Test & Code - Software Testing, Development, Python

Links:

<p>In today&#39;s episode we talk with Kelly Paredes &amp; Sean Tibor. <br> They teach Python in a middle school in Florida, and talk about this experience on the podcast <q>Teaching Python</q>.</p> <p>I love that they include physical computing right from the start, and everything else they are doing.</p> <p>It&#39;s a fun interview.</p><p>Special Guests: Kelly Paredes and Sean Tibor.</p><p>Sponsored By:</p><ul><li><a rel="nofollow" href="http://testandcode.com/pycharm">PyCharm Professional</a>: <a rel="nofollow" href="http://testandcode.com/pycharm">Try PyCharm Pro for an extended 4 month trial before deciding which version you need. If you value your time, you owe it to yourself to try PyCharm.</a> Promo Code: TESTNCODE2019</li></ul><p><a rel="payment" href="https://www.patreon.com/testpodcast">Support Test &amp; Code - Software Testing, Development, Python</a></p><p>Links:</p><ul><li><a title="Teaching Python" rel="nofollow" href="https://www.teachingpython.fm/">Teaching Python</a></li></ul>

from Planet Python
via read more

Stack Abuse: Doubly Linked List with Python Examples

This is the third article in the series of articles on implementing linked list with Python. In Part 1 and Part 2 of the series we studied single linked list in detail. In this article, we will start our discussion about doubly linked list, which is actually an extension of single linked list.

In single linked list each node of the list has two components, the actual value of the node and the reference to the next node in the linked list. In the doubly linked list, each node has three components: the value of the node, the reference to the previous node, and the reference to the next node. For the start node of the doubly linked list, the reference to the previous node is null. Similarly, for the last node in the doubly linked list, the reference to next node is null.

Pros and Cons of a Doubly Linked List

Following are some of the pros and cons of a doubly linked list:

Pros

  • Unlike a single linked list, the doubly linked list can be traversed and searched in both directions. The reference to the next node helps in traversing the node in the forward direction while the references to the previous nodes allow traversal in the backward direction.
  • Basic operations such as insertion and deletion are easier to implement in the doubly linked lists since, unlike single linked lists, we do not need to traverse to the predecessor node and store its reference. Rather, in a doubly linked list the reference of the predecessor node can be retrieved from the node that we want to delete.

Cons

  • One of the major drawbacks of the doubly linked list is that you need more memory space to store one extra reference for each node.
  • A few additional steps are required to be performed in order to perform insertion and deletion operations.

Implementing the Doubly Linked List with Python

In this section, we will see how we can create a very simple doubly linked list in Python. If you have read Part 1 and Part 2 of this series of articles, the code should be pretty straight-forward.

As always, let's first create a class for the single node in the list. Add the following code to your file:

class Node:  
    def __init__(self, data):
        self.item = data
        self.nref = None
        self.pref = None

You can see in the above code, we create a Node class with three member variables: item, nref, and pref. The item variable will store the actual data for the node. The nref stores the reference to the next node, while pref stores the reference to the previous node in the doubly linked list.

Next, we need to create the DoublyLinkedList class, which contains different doubly linked list related functions. Add the following code:

class DoublyLinkedList:  
    def __init__(self):
        self.start_node = None

Throughout this article we will keep adding functions to this class.

Inserting Items in Doubly Linked List

In this section, we will see the different ways of inserting items in a doubly linked list.

Inserting Items in Empty List

The easiest way to insert an item in a doubly linked list is to insert an item in the empty list. The following script inserts an element at the start of the doubly linked list:

 def insert_in_emptylist(self, data):
        if self.start_node is None:
            new_node = Node(data)
            self.start_node = new_node
        else:
            print("list is not empty")

In the script above, we define a method insert_in_emptylist(). The method first checks whether the self.start_node variable is None or not. If the variable is None, it means that the list is actually empty. Next, a new node is created and its value is initialized by the value passed as a parameter to the data parameter of the insert_in_emptylist() function. Finally, the value of self.start_node variable is set to the new node. In case if the list is not empty, a message is simply displayed to the user that the list is not empty.

Add the insert_in_emptylist() method to the DoublyLinkedList class that you created earlier.

Inserting Items at the Start

To insert an item at the beginning of the doubly linked list, we have to first check whether the list is empty or not. If the list is empty, we can simply use the logic defined in the insert_in_emptylist() to insert the element since in an empty list, the first element is always at the start.

Else, if the list is not empty, we need to perform three operations:

  1. For the new node, the reference to the next node will be set to self.start_node.
  2. For the self.start_node the reference to the previous node will be set to the newly inserted node.
  3. Finally, the self.start_node will become the newly inserted node.

The following script inserts an item at the start of the doubly linked list:

    def insert_at_start(self, data):
        if self.start_node is None:
            new_node = Node(data)
            self.start_node = new_node
            print("node inserted")
            return
        new_node = Node(data)
        new_node.nref = self.start_node
        self.start_node.pref = new_node
        self.start_node = new_node

Add the insert_at_start() method to the DoublyLinkedList class that you created earlier.

Inserting Items at the End

Inserting an element at the end of the doubly linked list is somewhat similar to inserting an element at the start. At first, we need to check if the list is empty. If the list is empty then we can simply use the insert_in_emptylist() method to insert the element. If the list already contains some element, we traverse through the list until the reference to the next node becomes None. When the next node reference becomes None it means that the current node is the last node.

The previous reference for the new node is set to the last node, and the next reference for the last node is set to the newly inserted node. The script for inserting an item at the last node is as follows:

    def insert_at_end(self, data):
        if self.start_node is None:
            new_node = Node(data)
            self.start_node = new_node
            return
        n = self.start_node
        while n.nref is not None:
            n = n.nref
        new_node = Node(data)
        n.nref = new_node
        new_node.pref = n

Add the insert_at_end() method to the DoublyLinkedList class that you created earlier.

Inserting Item after another Item

To insert an item after another item, we first check whether or not the list is empty. If the list is actually empty, we simply display the message that the "list is empty".

Otherwise we iterate through all the nodes in the doubly linked list. In case if the node after which we want to insert the new node is not found, we display the message to the user that the item is not found. Else if the node is found, it is selected and we perform four operations:

  1. Set the previous reference of the newly inserted node to the selected node.
  2. Set the next reference of the newly inserted node to the next reference of the selected.
  3. If the selected node is not the last node, set the previous reference of the next node after the selected node to the newly added node.
  4. Finally, set the next reference of the selected node to the newly inserted node.

The script for inserting item after another item is as follows:

    def insert_after_item(self, x, data):
        if self.start_node is None:
            print("List is empty")
            return
        else:
            n = self.start_node
            while n is not None:
                if n.item == x:
                    break
                n = n.nref
            if n is None:
                print("item not in the list")
            else:
                new_node = Node(data)
                new_node.pref = n
                new_node.nref = n.nref
                if n.nref is not None:
                    n.nref.prev = new_node
                n.nref = new_node

Add the insert_after_item() method to the DoublyLinkedList class that you created earlier.

Inserting Item before another Item

To insert an item before another item, we first check whether or not the list is empty. If the list is actually empty, we simply display the message that the "list is empty".

Otherwise we iterate through all the nodes in the doubly linked list. In case if the node before which we want to insert the new node is not found, we display the message to the user that the item is not found. Else if the node is found, it is selected and we perform four operations:

  1. Set the next reference of the newly inserted node to the selected node.
  2. Set the previous reference of the newly inserted node to the previous reference of the selected.
  3. Set the next reference of the node previous to the selected node, to the newly added node.
  4. Finally, set the previous reference of the selected node to the newly inserted node.

The script for adding item before another item in a doubly linked list is as follows:

    def insert_before_item(self, x, data):
        if self.start_node is None:
            print("List is empty")
            return
        else:
            n = self.start_node
            while n is not None:
                if n.item == x:
                    break
                n = n.nref
            if n is None:
                print("item not in the list")
            else:
                new_node = Node(data)
                new_node.nref = n
                new_node.pref = n.pref
                if n.pref is not None:
                    n.pref.nref = new_node
                n.pref = new_node

Add the insert_before_item() method to the DoublyLinkedList class that you created earlier.

Traversing a Doubly Linked List

Traversing a doubly linked list is very similar to traversing a single linked list. The script is as follows:

    def traverse_list(self):
        if self.start_node is None:
            print("List has no element")
            return
        else:
            n = self.start_node
            while n is not None:
                print(n.item , " ")
                n = n.nref

Add the traverse_list() method to the DoublyLinkedList class that you created earlier.

Deleting Elements from Doubly Linked List

Like insertion, there can be multiple ways to delete elements from a doubly linked list. In this section, we will review some of them.

Deleting Elements from the Start

The easiest way to delete an element from a doubly linked list is from the start. To do so, all you have to do is set the value of the start node to the next node and then set the previous reference of the start node to None. However before we do that we need to perform two checks. First, we need to see if the list is empty. And then we have to see if the list contains only one element or not. If the list contains only one element then we can simply set the start node to None. The following script can be used to delete elements from the start of the doubly linked list.

   def delete_at_start(self):
        if self.start_node is None:
            print("The list has no element to delete")
            return 
        if self.start_node.nref is None:
            self.start_node = None
            return
        self.start_node = self.start_node.nref
        self.start_prev = None;

Add the delete_at_start() method to the DoublyLinkedList class that you created earlier.

Deleting Elements from the End

To delete the element from the end, we again check if the list is empty or if the list contains a single element. If the list contains a single element, all we have to do is to set the start node to None. If the list has more than one element, we iterate through the list until the last node is reached. Once we reach the last node, we set the next reference of the node previous to the last node, to None which actually removes the last node. The following script can be used to delete the element from the end.

    def delete_at_end(self):
        if self.start_node is None:
            print("The list has no element to delete")
            return 
        if self.start_node.nref is None:
            self.start_node = None
            return
        n = self.start_node
        while n.nref is not None:
            n = n.nref
        n.pref.nref = None

Add the delete_at_end() method to the DoublyLinkedList class that you created earlier.

Deleting Elements by Value

Deleting an element by value is the trickiest of all the deletion functions in doubly linked lists since several cases have to be handled in order to remove an element by value. Let's first see how the function looks like and then we will see the explanation of the individual piece of code.

    def delete_element_by_value(self, x):
        if self.start_node is None:
            print("The list has no element to delete")
            return 
        if self.start_node.nref is None:
            if self.start_node.item == x:
                self.start_node = None
            else:
                print("Item not found")
            return 

        if self.start_node.item == x:
            self.start_node = self.start_node.nref
            self.start_node.pref = None
            return

        n = self.start_node
        while n.nref is not None:
            if n.item == x:
                break;
            n = n.nref
        if n.nref is not None:
            n.pref.nref = n.nref
            n.nref.pref = n.pref
        else:
            if n.item == x:
                n.pref.nref = None
            else:
                print("Element not found")

In the above script we create delete_element_by_value() function that takes the node value as parameter and deletes that node. At the beginining of the function we check if the list is empty or not. If the list is empty we simply display the user that the list is empty.

This logic is implemented in the following piece of code:

        if self.start_node is None:
            print("The list has no element to delete")
            return 

Next, we check if the list has a single element and that element is actually the element we want to delete. If the only element is the one that we want to delete, we simply set the self.start_node to None which means that the list will now have no item. If there is only one item and that is not the item that we want to delete, we will simply display the message that item to be deleted is not found.

The following piece of code implements this logic:

        if self.start_node.nref is None:
            if self.start_node.item == x:
                self.start_node = None
            else:
                print("Item not found")
            return 

Next, we handle the case where the list has more than one items but the item to be deleted is the first item. In that case we simply execute the logic that we wrote for the method delete_at_start(). The following piece of code deletes an element from the start in case of multiple items:

        if self.start_node.item == x:
            self.start_node = self.start_node.nref
            self.start_node.pref = None
            return

Finally, if the list contains multiple items and the item to be deleted is not the first item, we traverse all the elements in the list except the last one and see if any of the nodes has the value that matches the value be deleted. If the node is found, we perform the following two operations:

  1. Set the value of the next reference of the previous node to the next reference of the node to be deleted.
  2. Set the previous value of the next node to the previous reference of the node to be deleted.

Finally, if the node to be deleted is the last node, the next reference of the node previous to the last node is set to None. The following script implements this logic:

        n = self.start_node
        while n.nref is not None:
            if n.item == x:
                break;
            n = n.nref
        if n.nref is not None:
            n.pref.nref = n.nref
            n.nref.pref = n.pref
        else:
            if n.item == x:
                n.pref.nref = None
            else:
                print("Element not found")

Add the delete_element_by_value() method to the DoublyLinkedList class that you created earlier.

Reversing a Doubly Linked List

To reverse a doubly linked list, you basically have to perform the following operations:

  1. The next reference of the start node should be set none because the first node will become the last node in the reversed list.
  2. The previous reference of the last node should be set to None since the last node will become the previous node.
  3. The next references of the nodes (except the first and last node) in the original list should be swapped with the previous references.

The script for reversing a doubly linked list is as follows:

    def reverse_linked_list(self):
        if self.start_node is None:
            print("The list has no element to delete")
            return 
        p = self.start_node
        q = p.nref
        p.nref = None
        p.pref = q
        while q is not None:
            q.pref = q.nref
            q.nref = p
            p = q
            q = q.pref
        self.start_node = p

Add the reverse_linked_list() method to the DoublyLinkedList class that you created earlier.

Testing Doubly Linked List Functions

In this section, we will test the doubly linked functions that we created in the previous sections.

Let's first create the object of the DoublyLinkedList class. Execute the following script:

new_linked_list = DoublyLinkedList()  

Testing Insertion Functions

Let's test the insertion functions first. We'll first add elements in the empty list. Execute the following script:

new_linked_list.insert_in_emptylist(50)  

Now if you traverse the list, you should see 50 as the only element in the list as shown below:

new_linked_list.traverse_list()  

Output:

50  

Now let's add a few elements at the start. Execute the following script:

new_linked_list.insert_at_start(10)  
new_linked_list.insert_at_start(5)  
new_linked_list.insert_at_start(18)  

Now if you traverse the list, you should see the following elements in the list:

18  
5  
10  
50  

To add the elements at the end, execute the following script:

new_linked_list.insert_at_end(29)  
new_linked_list.insert_at_end(39)  
new_linked_list.insert_at_end(49)  

Now if you traverse the doubly linked list, you should see the following elements:

18  
5  
10  
50  
29  
39  
49  

Let's insert an element after 50.

new_linked_list.insert_after_item(50, 65)  

Now the list should look like this:

18  
5  
10  
50  
65  
29  
39  
49  

Finally, let's add an element before item 29.

new_linked_list.insert_before_item(29, 100)  

The list at this point of time, should contain the following elements:

18  
5  
10  
50  
65  
100  
29  
39  
49  

Testing Deletion Functions

Let's now test the deletion functions on the items that we inserted in the last sections. Let's first delete an element from the start.

new_linked_list.delete_at_start()  

Item 18 will be removed and the list will now look like this:

5  
10  
50  
65  
100  
29  
39  
49  

Similarly, the following script deletes the element from the end of the doubly linked list:

new_linked_list.delete_at_end()  

Traversing the list now will return the following items:

5  
10  
50  
65  
100  
29  
39  

Finally, you can also delete the elements by value using the delete_element_by_value() function as shown below:

new_linked_list.delete_element_by_value(65)  

If you traverse the list now, you will see that item 65 will be deleted from the list.

Testing Reverse Function

Finally, let's reverse the list using the reverse_linked_list() function. Execute the following script:

new_linked_list.reverse_linked_list()  

Now if you traverse the list, you will see the reversed linked list:

39  
29  
100  
50  
10  
5  

Conclusion

The doubly linked list is extremely useful specifically when you have to perform lots of inserts and delete operations. The links to the previous and next nodes make it very easy to insert and delete new elements without keeping track of the previous and next nodes.

In this article, we saw how doubly linked list can be implemented with Python. We also saw different ways to perform insert and delete operations on doubly linked list. Finally we studied how to reverse a doubly linked list.



from Planet Python
via read more

PyCharm: PyCharm 2019.1 EAP 6

A variable viewer for our native Jupyter Notebook support, an interpreter indicator in the status bar, and more. Try the PyCharm 2019.1 EAP now, you can download the latest version on our website.

New in This Version

Variable Viewer for Jupyter Notebooks

Notebooks Variable

Last week we’ve introduced our new Jupyter Notebooks support, that allows you to directly edit and run .ipynb files from PyCharm. This week, we’re adding some more functionality.

Have you ever lost track of the state of your Jupyter Notebook as you’re working with it? We’ve now added a variables viewer to our new Jupyter Notebook support, so you can easily see what’s going on.

Interpreter Indicator

Interpreter Chooser

Are you in the process of migrating to a new version of a framework, or even a new version of Python? PyCharm now makes it even easier to switch between interpreters. Just choose it right from the status bar. If you prefer to keep your hands on your keyboard, use Ctrl+Shift+A to find action, and look for ‘Switch Python interpreter’.

Further Improvements

Interested?

Download this EAP from our website. Alternatively, you can use the JetBrains Toolbox App to stay up to date throughout the entire EAP.

With PyCharm 2019.1 we’re moving to a new runtime environment: this EAP build already bundles the brand new JetBrains Runtime Environment (a customized version of JRE 11). Unfortunately, since this build uses the brand-new platform, the patch-update from previous versions is not available this time. Please use the full installation method instead.

If you tried 2019.1 EAP 3 or an earlier EAP of 2019.1: you may get an error about “MaxJavaStackTraceDepth=-1” when you start the IDE. If you get it, please remove that line from the custom JVM options. This is an incompatibility between the old JRE and the new one, and we apologize for any inconvenience.

If you’re on Ubuntu 16.04 or later, you can use snap to get PyCharm EAP, and stay up to date. You can find the installation instructions on our website.

PyCharm 2019.1 is in development during the EAP phase, therefore not all new features are already available. More features will be added in the coming weeks. As PyCharm 2019.1 is pre-release software, it is not as stable as the release versions. Furthermore, we may decide to change and/or drop certain features as the EAP progresses.

All EAP versions will ship with a built-in EAP license, which means that these versions are free to use for 30 days after the day that they are built. As EAPs are released weekly, you’ll be able to use PyCharm Professional Edition EAP for free for the duration of the EAP program, as long as you upgrade at least once every 30 days.



from Planet Python
via read more

PyCharm 2019.1 EAP 6

A variable viewer for our native Jupyter Notebook support, an interpreter indicator in the status bar, and more. Try the PyCharm 2019.1 EAP now, you can download the latest version on our website.

New in This Version

Variable Viewer for Jupyter Notebooks

Notebooks Variable

Last week we’ve introduced our new Jupyter Notebooks support, that allows you to directly edit and run .ipynb files from PyCharm. This week, we’re adding some more functionality.

Have you ever lost track of the state of your Jupyter Notebook as you’re working with it? We’ve now added a variables viewer to our new Jupyter Notebook support, so you can easily see what’s going on.

Interpreter Indicator

Interpreter Chooser

Are you in the process of migrating to a new version of a framework, or even a new version of Python? PyCharm now makes it even easier to switch between interpreters. Just choose it right from the status bar. If you prefer to keep your hands on your keyboard, use Ctrl+Shift+A to find action, and look for ‘Switch Python interpreter’.

Further Improvements

Interested?

Download this EAP from our website. Alternatively, you can use the JetBrains Toolbox App to stay up to date throughout the entire EAP.

With PyCharm 2019.1 we’re moving to a new runtime environment: this EAP build already bundles the brand new JetBrains Runtime Environment (a customized version of JRE 11). Unfortunately, since this build uses the brand-new platform, the patch-update from previous versions is not available this time. Please use the full installation method instead.

If you tried 2019.1 EAP 3 or an earlier EAP of 2019.1: you may get an error about “MaxJavaStackTraceDepth=-1” when you start the IDE. If you get it, please remove that line from the custom JVM options. This is an incompatibility between the old JRE and the new one, and we apologize for any inconvenience.

If you’re on Ubuntu 16.04 or later, you can use snap to get PyCharm EAP, and stay up to date. You can find the installation instructions on our website.

PyCharm 2019.1 is in development during the EAP phase, therefore not all new features are already available. More features will be added in the coming weeks. As PyCharm 2019.1 is pre-release software, it is not as stable as the release versions. Furthermore, we may decide to change and/or drop certain features as the EAP progresses.

All EAP versions will ship with a built-in EAP license, which means that these versions are free to use for 30 days after the day that they are built. As EAPs are released weekly, you’ll be able to use PyCharm Professional Edition EAP for free for the duration of the EAP program, as long as you upgrade at least once every 30 days.



from PyCharm Blog
read more

Wednesday, February 27, 2019

gamingdirectional: The mana detection mechanism

Finally, in this chapter, we will look at the mana detection mechanism where when the player has overlapped mana he will gain 1 unit of life so when he hits the enemy he can continue to move onward after he has used that 1 unit of life to heal himself. We will also remove the enemy from the scene after it has collided with the player. In order to create such a system, we need to edit a few files.

Source



from Planet Python
via read more

codingdirectional: Include the currency name into the forex application

Hello and welcome back to this new python forex application project. In the previous chapter, we have successfully retrieved the name and the id pair for all the conbase supported currencies, and in this chapter, we will use that information to add the currency name beside each currency id when we are comparing that currency to the USD. Below is the modify version of this program.

from coinbase.wallet.client import Client
import json
from tkinter import *
import tkinter.ttk as tk

win = Tk() # Create tk instance
win.title("Real CryptoGeek") # Add a title
win.resizable(0, 0) # Disable resizing the GUI
win.configure(background='white') # change background color

s = StringVar() # change text
currencyFrame = Frame(win) # create currency frame
currencyFrame.pack(side=TOP)
currency = Label(currencyFrame)
currency.pack()
text_widget = Text(currency, fg='white', background='black')
text_widget.pack()

s.set("Click the below button to find out the bitcoin exchange rate")
text_widget.insert(END, s.get())

buttonFrame = Frame(win) # create a button frame
buttonFrame.pack(side = BOTTOM, fill=X, pady = 6)

def get_exchange_rate():

    f = open("coin.txt", "r")
    api_key = f.readline()
    api_secret = f.readline()
    f.close()

    sell_buy = ''

    api_key = api_key.replace('\n', '')
    api_secret = api_secret.replace('\n', '')

    try:
        client = Client(api_key, api_secret)
        market_currencies_o = client.get_exchange_rates()
        market_currencies_s = json.dumps(market_currencies_o)
        exchange_rate = json.loads(market_currencies_s)
        supported_currency = client.get_currencies() # get all the available currencies
        exchange_rate_s = json.loads(json.dumps(supported_currency))

    except:
        print("An exception occurred")

    exchange_name_dict = dict()

    for key in exchange_rate_s['data']:
        id = key['id']
        name = key['name']
        obj_currency = {id:name}
        exchange_name_dict.update(obj_currency)

    count = 0
    found = False
    for key in exchange_rate['rates']:
        count += 1
        for e_key in exchange_name_dict:
            if(e_key == key):
                sell_buy += str(count) + ".) Pair : " + exchange_rate['currency'] + "/" + key + " (" + exchange_name_dict[e_key] + ") : " + \
                exchange_rate['rates'][key] + '\n'
                found = True
                break
        if(found == False):
            sell_buy += str(count) + ".) Pair : " + exchange_rate['currency'] + "/" + key + " : " + \
                exchange_rate['rates'][key] + '\n'
        else:
            found = False

    text_widget.delete('1.0', END) # clear all those previous text first
    s.set(sell_buy)
    text_widget.insert(INSERT, s.get())

action_vid = tk.Button(buttonFrame, text="Find", command=get_exchange_rate) # find out the exchange rate of bitcoin
action_vid.pack(fill=X)
win.mainloop()

By introducing the new exchange name dictionary to the above program, that program can now place the currency name next to the id of that currency if that name is inside the object returned by the coinbase API.

Like, share or follow me on twitter. In the next chapter, we will continue to develop this new forex application. This website depends on the reader supports to survive, if you have cryptocurrency do consider to donate to this website.

  • Bitcoin
  • Bitcoin cash
  • Litecoin
  • Stellar
Scan to Donate Bitcoin to 38han7NG6KHtxZsS4ppTwAtSw7UfLSY5Vd

Donate Bitcoin to this address

Scan the QR code or copy the address below into your wallet to send some Bitcoin

Scan to Donate Bitcoin cash to qqegrlxc93q5ah0s2s6w9zxwf685vr26nu0kxlkvpc

Donate Bitcoin cash to this address

Scan the QR code or copy the address below into your wallet to send some Bitcoin cash

Scan to Donate Litecoin to MJJ2T1XyD4NtSjTA3NpcqTuaTaCKfT3fdA

Donate Litecoin to this address

Scan the QR code or copy the address below into your wallet to send some Litecoin

Scan to Donate Stellar to GAJRUOEMPNSHHR2ZB4KOOQ3MIR2BN54BBXGHTYA6QWMGST7AGI46WIHU

Donate Stellar to this address

Scan the QR code or copy the address below into your wallet to send some Stellar



from Planet Python
via read more

Talk Python to Me: #201 Choosing JupyterHub and Python over MATLAB

The Nobel prize in economics recently went to Paul Romer, a convert from proprietary software like Matlab over to Python and the SciPy stack. Paul said, “The more I learn about proprietary software, the more I worry that objective truth might perish from the earth.”

from Planet Python
via read more

PyCharm: PyCharm 2018.3.5

We’ve release a minor update to PyCharm 2018.3, you can now download PyCharm 2018.3.5 from our website.

New in This Version

  • If you have a private key with a passphrase, and would use to like native ssh rather than our built-in client for accessing remote git repositories, you’re now able to enter your passphrase in a dialog. This was previously only possible in combination with ssh-agent.
  • The behavior of search everywhere was adjusted to rank partial filename matches higher in the results. See IDEA-203491
  • The plugins redesign lead to issues with installing plugins offline. This has been resolved.
  • And more, see the release notes for details

Updating PyCharm

You can update PyCharm by choosing Help | Check for Updates (or PyCharm | Check for Updates on macOS) in the IDE. PyCharm will be able to patch itself to the new version, there should no longer be a need to run the full installer.

If you’re on Ubuntu 16.04 or later, or any other Linux distribution that supports snap, you should not need to upgrade manually, you’ll automatically receive the new version.



from Planet Python
via read more

Stack Abuse: Introduction to the Python Pathlib Module

The Pathlib module in Python simplifies the way in working with files and folders. The Pathlib module is available from Python 3.4 and higher versions. It combines the best of Python's file system modules namely os, os.path, glob, etc.

In Python, most of the scripts involve interacting with file systems. Hence, it is important to deal with file names and paths. To achieve this, Python includes the Pathlib module which contains useful functions to perform file-related tasks. Pathlib provides a more readable and easier way to build up paths by representing filesystem paths as proper objects and enables us to write code that is portable across platforms.

In this article, we will study the Pathlib module in detail with the help of various examples.

The Concept of Path and Directory

Before moving further into details of the Pathlib module, it's important to understand 2 different concepts namely - path and directory.

The path is used to identify a file. The path provides an optional sequence of directory names terminated by the final file name including the filename extension. The filename extension provides some information about the file format/ contents. The Pathlib module can deal with absolute as well as relative paths. An absolute path begins from the root directory and specifies the complete directory tree, whereas a relative path, as the name suggests, is the path of a file relative to another file or directory (usually the current directory).

Directory represents the filesystem entry of the path and it includes file name, creation time, size, owner, etc.

The Pathlib module in Python deals with path related tasks, such as constructing new paths from names of files and from other paths, checking for various properties of paths and creating files and folders at specific paths.

How to use the Pathlib Module?

To use the pathlib module conveniently within our scripts, we import all the classes in it using:

from pathlib import *  

As a first task, let's retrieve the current working directory and home directory objects, respectively, using the code below:

current_dir = Path.cwd()  
home_dir = Path.home()  
print(current_dir)  
print(home_dir)  

We can choose to import pathlib instead of importing all the classes. In that case, all the subsequent uses of classes within the module should be prefixed with pathlib.

import pathlib

current_dir = pathlib.Path.cwd()  
home_dir = pathlib.Path.home()  
print(current_dir)  
print(home_dir)  

Why use the Pathlib Module?

If you've been working with the Python language for a while, you would be wondering what is the necessity of Pathlib module when os, os.path, glob, etc. modules are already available? This is a fully justified concern. Let's try to address this via an example.

Let's say we want to make a file called "output/output.xlsx" within the current working directory. The following code tries to achieve this using the os.path module. For this, os.getcwd and os.path.join functions are used.

import os  
outpath = os.path.join(os.getcwd(), 'output')  
outpath_file = os.path.join(outpath, 'out.xlsx')  

Alternately,

outpath_file = os.pathjoin(os.path.join(os.getcwd(), 'output'), "out.xlsx")  

Though the code works, it looks clunky and is not readable nor easy to maintain. Imagine how this code would look if we wanted to create a new file inside multiple nested directories.

The same code can be re-written using Pathlib module, as follows:

from pathlib import Path  
outpath = Path.cwd() / 'output' / 'output.xlsx'  

This format is easier to parse mentally. In Pathlib, the Path.cwd() function is used to get the current working directory and / operator is used in place of os.path.join to combine parts of the path into a compound path object. The function nesting pattern in the os.path module is replaced by the Path class of Pathlib module that represents the path by chaining methods and attributes. The clever overloading of the / operator makes the code readable and easy to maintain.

Another benefit of the method provided by the Pathlib module is that a Path object is created rather than creating a string representation of the path. This object has several handy methods that make life easier than working with raw strings that represent paths.

Performing Operations on Paths

The classic os.path module is used only for manipulating path strings. To do something with the path, for example, creating a directory, we need the os module. The os module provides a set of functions for working with files and directories, like: mkdir for creating a directory, rename to rename a directory, getsize to get the size of a directory and so on.

Let's write some of these operations using the os module and then rewrite the same code using the Pathlib module.

Sample code written using os module:

if os.path.isdir(path):  
    os.rmdir(path)

If we use Pathlib module's path objects to achieve the same functionality, the resulting code will be much more readable and easier to maintain as shown below:

if path.is_dir()  
    path.rmdir()

It is cumbersome to find path related utilies in the os module. The Pathlib module solves the problem by replacing the utilities of os module with methods on path objects. Let us understand it even better with a code:

outpath = os.path.join(os.getcwd(), 'output')  
outpath_tmp = os.path.join(os.getcwd(), 'output.tmp')  
generate_data(output_tmp)

if os.path.getsize(output_tmp):  
    os.rename(outpath_tmp, outpath)
else: # Nothing produced  
    os.remove(outpath_tmp)

Here, the function generate_data() takes a file path as a parameter and writes data to another path. However, if the file that is passed as a parameter is not changed, since the last time the generate_data() function was executed, an empty file is generated. In that case, the empty file is replaced with the previous version of the file.

The variable outpath stores the data by joining the current working directory with the filename "output". We create a temp version, as well, named as outpath.tmp. If the size of temp version is not zero, which implies that it is not an empty file, then the temp version is renamed to outpath, otherwise the temp version is removed and the old version is retained.

Using the os module, manipulating paths of filesystems as string objects become clumsy as there are multiple calls to os.path.join(), os.getcwd(), etc. To avoid this problem, the Pathlib module offers a set of classes that can be used for frequently used operations on the path, in a more readable, simple, object-oriented way.

Let's try to re-write the above code using Pathlib module.

from pathlib import Path

outpath = Path.cwd() / 'output'  
outpath_tmp = Path.cwd() / 'output_tmp'

generate_data(output_tmp)

if outpath_tmp.stat().st_size:  
    outpath_tmp.rename(outpath)
else: # Nothing produced  
    Path_tmp.unlink()

Using Pathlib, os.getcwd() becomes Path.cwd() and '/' operator is used to join paths and used in place of os.path.join. Using the Pathlib module, things can be done in a simpler way using operators and method calls.

Following are commonly used methods and it's usage:

  • Path.cwd(): Return path object representing the current working directory
  • Path.home(): Return path object representing the home directory
  • Path.stat(): return info about the path
  • Path.chmod(): change file mode and permissions
  • Path.glob(pattern): Glob the pattern given in the directory that is represented by the path, yielding matching files of any kind
  • Path.mkdir(): to create a new directory at the given path
  • Path.open(): To open the file created by the path
  • Path.rename(): Rename a file or directory to the given target
  • Path.rmdir(): Remove the empty directory
  • Path.unlink(): Remove the file or symbolic link

Generating Cross-Platform Paths

Paths use different conventions in different Operating Systems. Windows uses a backslash between folder names, whereas all other popular Operating Systems uses forward slash between folder names. If you want your python code to work, irrespective of the underlying OS, you'll need to handle the different conventions specific to the underlying platform. The Pathlib module makes working with file paths easier. In Pathlib, you can just pass a path or filename to Path() object using forward slash, irrespective of the OS. Pathlib handles the rest.

pathlib.Path.home() / 'python' / 'samples' / 'test_me.py'  

The Path() object will covert the / to the apt kind of slash, for the underlying Operating System. The pathlib.Path may represent either Windows or Posix path. Thus, Pathlib solves a lot of cross-functional bugs, by handling paths easily.

Getting Path Information

While dealing with paths, we are interested in finding the parent directory of a file/folder or in following symbolic links. Path class has several convenient methods for doing this, as different parts of a path are available as properties that include the following:

  • drive: a string that represents the drive name. For example, PureWindowsPath('c:/Program Files/CSV').drive returns "C:"
  • parts: returns a tuple that provides access to the path's components
  • name: the path component without any directory
  • parent: sequence providing access to the logical ancestors of the path
  • stem: final path component without its suffix
  • suffix: the file extension of the final component
  • anchor: the part of a path before the directory. / is used to create child paths and mimics the behavior of os.path.join.
  • joinpath: combines the path with the arguments provided
  • match(pattern): returns True/False, based on matching the path with the glob-style pattern provided

In path "/home/projects/stackabuse/python/sample.md":

  • path: - returns PosixPath('/home/projects/stackabuse/python/sample.md')
  • path.parts: - returns ('/', 'home', 'projects', 'stackabuse', 'python')
  • path.name: - returns 'sample.md'
  • path.stem: - returns 'sample'
  • path.suffix: - returns '.md'
  • path.parent: - returns PosixPath('/home/projects/stackabuse/python')
  • path.parent.parent: - returns PosixPath('/home/projects/stackabuse')
  • path.match('*.md'): returns True
  • PurePosixPath('/python').joinpath('edited_version'): returns ('home/projects/stackabuse/python/edited_version

Alternative of the Glob Module

Apart from os , os.path modules, glob module is also available in Python that provides file path related utils. glob.glob function of the glob module is used to find files matching a pattern.

from glob import glob

top_xlsx_files = glob('*.xlsx')  
all_xlsx_files = glob('**/*.xlsx', recursive=True)  

The pathlib provides glob utilities, as well:

from pathlib import Path

top_xlsx_files = Path.cwd().glob('*.xlsx')  
all_xlsx_files = Path.cwd().rglob('*.xlsx')  

The glob functionality is available with Path objects. Thus, pathlib modules make complex tasks simpler.

Reading and Writing Files using Pathlib

The following methods are used to perform basic operations like reading and writing files:

  • read_text: File is opened in text mode to read the contents of the file and close it after reading
  • read_bytes: Used to open the file in binary mode and return contents in binary form and closes the file after the same.
  • write_text: Used to open the file and writes text and closes it later
  • write_bytes: Used to write binary data to a file and closes the file, once done

Let's explore the usage of the Pathlib module for common file operations. The following example is used to read the contents of a file:

path = pathlib.Path.cwd() / 'Pathlib.md'  
path.read_text()  

Here, read_text method on Path object is used to read the contents of the file.
Below example is used to write data to a file, in text mode:

from pathlib import Path

p = Path('sample_text_file') p.write_text('Sample to write data to a file')  

Thus, in the Pathlib module, by having the path as an object enables us to perform useful actions on the objects for file system involving lots of path manipulation like creating or removing directories, looking for specific files, moving files etc.

Conclusion

To conclude, the Pathlib module provides a huge number of rich and useful features that can be used to perform a variety of path related operations. As an added advantage the library is consistent across the underlying Operating System.



from Planet Python
via read more

Real Python: Traditional Face Detection With Python

Computer vision is an exciting and growing field. There are tons of interesting problems to solve! One of them is face detection: the ability of a computer to recognize that a photograph contains a human face, and tell you where it is located. In this article, you’ll learn about face detection with Python.

To detect any object in an image, it is necessary to understand how images are represented inside a computer, and how that objects differs visually from any other object.

Once that is done, the process of scanning an image and looking for those visual cues needs to be automated and optimized. All these steps come together to form a fast and reliable computer vision algorithm.

In this tutorial you’ll learn:

  • What face detection is
  • How computers understand features in images
  • How to quickly analyze many different features to reach a decision
  • How to use a minimal Python solution for detecting human faces in images

Free Bonus: Click here to get the Python Face Detection & OpenCV Examples Mini-Guide that shows you practical code examples of real-world Python computer vision techniques.

What Is Face Detection?

Face detection is a type of computer vision technology that is able to identify people’s faces within digital images. This is very easy for humans, but computers need precise instructions. The images might contain many objects that aren’t human faces, like buildings, cars, animals, and so on.

It is distinct from other computer vision technologies that involve human faces, like facial recognition, analysis, and tracking.

Facial recognition involves identifying the face in the image as belonging to person X and not person Y. It is often used for biometric purposes, like unlocking your smartphone.

Facial analysis tries to understand something about people from their facial features, like determining their age, gender, or the emotion they are displaying.

Facial tracking is mostly present in video analysis and tries to follow a face and its features (eyes, nose, and lips) from frame to frame. The most popular applications are various filters available in mobile apps like Snapchat.

All of these problems have different technological solutions. This tutorial will focus on a traditional solution for the first challenge: face detection.

How Do Computers “See” Images?

The smallest element of an image is called a pixel, or a picture element. It is basically a dot in the picture. An image contains multiple pixels arranged in rows and columns.

You will often see the number of rows and columns expressed as the image resolution. For example, an Ultra HD TV has the resolution of 3840x2160, meaning it is 3840 pixels wide and 2160 pixels high.

But a computer does not understand pixels as dots of color. It only understands numbers. To convert colors to numbers, the computer uses various color models.

In color images, pixels are often represented in the RGB color model. RGB stands for Red Green Blue. Each pixel is a mix of those three colors. RGB is great at modeling all the colors humans perceive by combining various amounts of red, green, and blue.

Since a computer only understand numbers, every pixel is represented by three numbers, corresponding to the amounts of red, green, and blue present in that pixel. You can learn more about color spaces in Image Segmentation Using Color Spaces in OpenCV + Python.

In grayscale (black and white) images, each pixel is a single number, representing the amount of light, or intensity, it carries. In many applications, the range of intensities is from 0 (black) to 255 (white). Everything between 0 and 255 is various shades of gray.

If each grayscale pixel is a number, an image is nothing more than a matrix (or table) of numbers:

Example of pixel values in a 3x3 grayscale imageExample 3x3 image with pixel values and colors

In color images, there are three such matrices representing the red, green, and blue channels.

What Are Features?

A feature is a piece of information in an image that is relevant to solving a certain problem. It could be something as simple as a single pixel value, or more complex like edges, corners, and shapes. You can combine multiple simple features into a complex feature.

Applying certain operations to an image produces information that could be considered features as well. Computer vision and image processing have a large collection of useful features and feature extracting operations.

Basically, any inherent or derived property of an image could be used as a feature to solve tasks.

Preparation

To run the code examples, you need to set up an environment with all the necessary libraries installed. The simplest way is to use conda.

You will need three libraries:

  1. scikit-image
  2. scikit-learn
  3. opencv

To create an environment in conda, run these commands in your shell:

$ conda create --name face-detection python=3.7
$ source activate face-detection
(face-detection)$ conda install scikit-learn
(face-detection)$ conda install -c conda-forge scikit-image
(face-detection)$ conda install -c menpo opencv3

If you are having problems installing OpenCV correctly and running the examples, try consulting their Installation Guide or the article on OpenCV Tutorials, Resources, and Guides.

Now you have all the packages necessary to practice what you learn in this tutorial.

Viola-Jones Object Detection Framework

This algorithm is named after two computer vision researchers who proposed the method in 2001: Paul Viola and Michael Jones.

They developed a general object detection framework that was able to provide competitive object detection rates in real time. It can be used to solve a variety of detection problems, but the main motivation comes from face detection.

The Viola-Jones algorithm has 4 main steps, and you’ll learn more about each of them in the sections that follow:

  1. Selecting Haar-like features
  2. Creating an integral image
  3. Running AdaBoost training
  4. Creating classifier cascades

Given an image, the algorithm looks at many smaller subregions and tries to find a face by looking for specific features in each subregion. It needs to check many different positions and scales because an image can contain many faces of various sizes. Viola and Jones used Haar-like features to detect faces.

Haar-Like Features

All human faces share some similarities. If you look at a photograph showing a person’s face, you will see, for example, that the eye region is darker than the bridge of the nose. The cheeks are also brighter than the eye region. We can use these properties to help us understand if an image contains a human face.

A simple way to find out which region is lighter or darker is to sum up the pixel values of both regions and comparing them. The sum of pixel values in the darker region will be smaller than the sum of pixels in the lighter region. This can be accomplished using Haar-like features.

A Haar-like feature is represented by taking a rectangular part of an image and dividing that rectangle into multiple parts. They are often visualized as black and white adjacent rectangles:

Example of 4 haar-like featuresBasic Haar-like rectangle features

In this image, you can see 4 basic types of Haar-like features:

  1. Horizontal feature with two rectangles
  2. Vertical feature with two rectangles
  3. Vertical feature with three rectangles
  4. Diagonal feature with four rectangles

The first two examples are useful for detecting edges. The third one detects lines, and the fourth one is good for finding diagonal features. But how do they work?

The value of the feature is calculated as a single number: the sum of pixel values in the black area minus the sum of pixel values in the white area. For uniform areas like a wall, this number would be close to zero and won’t give you any meaningful information.

To be useful, a Haar-like feature needs to give you a large number, meaning that the areas in the black and white rectangles are very different. There are known features that perform very well to detect human faces:

Haar-like feature applied on the human eyesHaar-like feature applied on the eye region. (Image: Wikipedia)

In this example, the eye region is darker than the region below. You can use this property to find which areas of an image give a strong response (large number) for a specific feature:

Haar-like feature applied on the bridge of the noseHaar-like feature applied on the bridge of the nose. (Image: Wikipedia)

This example gives a strong response when applied to the bridge of the nose. You can combine many of these features to understand if an image region contains a human face.

As mentioned, the Viola-Jones algorithm calculates a lot of these features in many subregions of an image. This quickly becomes computationally expensive: it takes a lot of time using the limited resources of a computer.

To tackle this problem, Viola and Jones used integral images.

Integral Images

An integral image (also known as a summed-area table) is the name of both a data structure and an algorithm used to obtain this data structure. It is used as a quick and efficient way to calculate the sum of pixel values in an image or rectangular part of an image.

In an integral image, the value of each point is the sum of all pixels above and to the left, including the target pixel:

Calculating an integral image from pixel valuesCalculating an integral image from pixel values

The integral image can be calculated in a single pass over the original image. This reduces summing the pixel intensities within a rectangle into only three operations with four numbers, regardless of rectangle size:

Selecting a rectangle in an integral imageCalculate the sum of pixels in the orange rectangle.

The sum of pixels in the rectangle ABCD can be derived from the values of points A, B, C, and D, using the formula D - B - C + A. It is easier to understand this formula visually:

Step by step calculation of a rectangle in an integral imageCalculating the sum of pixels step by step

You’ll notice that subtracting both B and C means that the area defined with A has been subtracted twice, so we need to add it back again.

Now you have a simple way to calculate the difference between the sums of pixel values of two rectangles. This is perfect for Haar-like features!

But how do you decide which of these features and in what sizes to use for finding faces in images? This is solved by a machine learning algorithm called boosting. Specifically, you will learn about AdaBoost, short for Adaptive Boosting.

AdaBoost

Boosting is based on the following question: “Can a set of weak learners create a single strong learner?” A weak learner (or weak classifier) is defined as a classifier that is only slightly better than random guessing.

In face detection, this means that a weak learner can classify a subregion of an image as a face or not-face only slightly better than random guessing. A strong learner is substantially better at picking faces from non-faces.

The power of boosting comes from combining many (thousands) of weak classifiers into a single strong classifier. In the Viola-Jones algorithm, each Haar-like feature represents a weak learner. To decide the type and size of a feature that goes into the final classifier, AdaBoost checks the performance of all classifiers that you supply to it.

To calculate the performance of a classifier, you evaluate it on all subregions of all the images used for training. Some subregions will produce a strong response in the classifier. Those will be classified as positives, meaning the classifier thinks it contains a human face.

Subregions that don’t produce a strong response don’t contain a human face, in the classifiers opinion. They will be classified as negatives.

The classifiers that performed well are given higher importance or weight. The final result is a strong classifier, also called a boosted classifier, that contains the best performing weak classifiers.

The algorithm is called adaptive because, as training progresses, it gives more emphasis on those images that were incorrectly classified. The weak classifiers that perform better on these hard examples are weighted more strongly than others.

Let’s look at an example:

Example of features to classify with AdaBoostThe blue and orange circles are samples that belong to different categories.

Imagine that you are supposed to classify blue and orange circles in the following image using a set of weak classifiers:

First classifier in the AdaBoost exampleThe first weak classifier classifies some of the blue circles correctly.

The first classifier you use captures some of the blue circles but misses the others. In the next iteration, you give more importance to the missed examples:

Changing the importance of samples in the AdaBoost exampleThe missed blue samples are given more importance, indicated by size.

The second classifier that manages to correctly classify those examples will get a higher weight. Remember, if a weak classifier performs better, it will get a higher weight and thus higher chances to be included in the final, strong classifiers:

Second classifier in the AdaBoost exampleThe second classifier captures the bigger blue circles.

Now you have managed to capture all of the blue circles, but incorrectly captured some of the orange circles. These incorrectly classified orange circles are given more importance in the next iteration:

Changing the importance of samples in the AdaBoost exampleThe misclassified orange circles are given more importance, and others are reduced.

The final classifier manages to capture those orange circles correctly:

Third classifier in the AdaBoost exampleThe third classifier captures the remaining orange circles.

To create a strong classifier, you combine all three classifiers to correctly classify all examples:

Final, strong classifier in the AdaBoost exampleThe final, strong classifier combines all three weak classifiers.

Using a variation of this process, Viola and Jones have evaluated hundreds of thousands of classifiers that specialize in finding faces in images. But it would be computationally expensive to run all these classifiers on every region in every image, so they created something called a classifier cascade.

Cascading Classifiers

The definition of a cascade is a series of waterfalls coming one after another. A similar concept is used in computer science to solve a complex problem with simple units. The problem here is reducing the number of computations for each image.

To solve it, Viola and Jones turned their strong classifier (consisting of thousands of weak classifiers) into a cascade where each weak classifier represents one stage. The job of the cascade is to quickly discard non-faces and avoid wasting precious time and computations.

When an image subregion enters the cascade, it is evaluated by the first stage. If that stage evaluates the subregion as positive, meaning that it thinks it’s a face, the output of the stage is maybe.

If a subregion gets a maybe, it is sent to the next stage of the cascade. If that one gives a positive evaluation, then that’s another maybe, and the image is sent to the third stage:

A single classifier in a cascadeA weak classifier in a cascade

This process is repeated until the image passes through all stages of the cascade. If all classifiers approve the image, it is finally classified as a human face and is presented to the user as a detection.

If, however, the first stage gives a negative evaluation, then the image is immediately discarded as not containing a human face. If it passes the first stage but fails the second stage, it is discarded as well. Basically, the image can get discarded at any stage of the classifier:

Cascading classifiers for face detectionA cascade of _n_ classifiers for face detection

This is designed so that non-faces get discarded very quickly, which saves a lot of time and computational resources. Since every classifier represents a feature of a human face, a positive detection basically says, “Yes, this subregion contains all the features of a human face.” But as soon as one feature is missing, it rejects the whole subregion.

To accomplish this effectively, it is important to put your best performing classifiers early in the cascade. In the Viola-Jones algorithm, the eyes and nose bridge classifiers are examples of best performing weak classifiers.

Now that you understand how the algorithm works, it is time to use it to detect faces with Python.

Using a Viola-Jones Classifier

Training a Viola-Jones classifier from scratch can take a long time. Fortunately, a pre-trained Viola-Jones classifier comes out-of-the-box with OpenCV! You will use that one to see the algorithm in action.

First, find and download an image that you would like to scan for the presence of human faces. Here’s an example:

Family stock photoExample stock photo for face detection (Image source)

Import OpenCV and load the image into memory:

import cv2 as cv

# Read image from your local file system
original_image = cv.imread('path/to/your-image.jpg')

# Convert color image to grayscale for Viola-Jones
grayscale_image = cv.cvtColor(original_image, cv.COLOR_BGR2GRAY)

Next, you need to load the Viola-Jones classifier. If you installed OpenCV from source, it will be in the folder where you installed the OpenCV library.

Depending on the version, the exact path might vary, but the folder name will be haarcascades, and it will contain multiple files. The one you need is called haarcascade_frontalface_alt.xml.

If for some reason, your installation of OpenCV did not get the pre-trained classifier, you can obtain it from the OpenCV GitHub repo:

# Load the classifier and create a cascade object for face detection
face_cascade = cv.CascadeClassifier('path/to/haarcascade_frontalface_alt.xml')

The face_cascade object has a method detectMultiScale(), which receives an image as an argument and runs the classifier cascade over the image. The term MultiScale indicates that the algorithm looks at subregions of the image in multiple scales, to detect faces of varying sizes:

detected_faces = face_cascade.detectMultiScale(grayscale_image)

The variable detected_faces now contains all the detections for the target image. To visualize the detections, you need to iterate over all detections and draw rectangles over the detected faces.

OpenCV’s rectangle() draws rectangles over images, and it needs to know the pixel coordinates of the top-left and bottom-right corner. The coordinates indicate the row and column of pixels in the image.

Luckily, detections are saved as pixel coordinates. Each detection is defined by its top-left corner coordinates and width and height of the rectangle that encompasses the detected face.

Adding the width to the row and height to the column will give you the bottom-right corner of the image:

for (column, row, width, height) in detected_faces:
    cv.rectangle(
        original_image,
        (column, row),
        (column + width, row + height),
        (0, 255, 0),
        2
    )

rectangle() accepts the following arguments:

  • The original image
  • The coordinates of the top-left point of the detection
  • The coordinates of the bottom-right point of the detection
  • The color of the rectangle (a tuple that defines the amount of red, green, and blue (0-255))
  • The thickness of the rectangle lines

Finally, you need to display the image:

cv.imshow('Image', original_image)
cv.waitKey(0)
cv.destroyAllWindows()

imshow() displays the image. waitKey() waits for a keystroke. Otherwise, imshow() would display the image and immediately close the window. Passing 0 as the argument tells it to wait indefinitely. Finally, destroyAllWindows() closes the window when you press a key.

Here’s the result:

Family stock photo with detected facesOriginal image with detections

That’s it! You now have a ready-to-use face detector in Python.

If you really want to train the classifier yourself, scikit-image offers a tutorial with the accompanying code on their website.

Further Reading

The Viola-Jones algorithm was an amazing achievement. Even though it still performs great for many use cases, it is almost 20 years old. Other algorithms exist, and they use different features

One example uses support vector machines (SVM) and features called histograms of oriented gradients (HOG). An example can be found in the Python Data Science Handbook.

Most current state-of-the-art methods for face detection and recognition use deep learning, which we will cover in a follow-up article.

For state-of-the-art computer vision research, have a look at the recent scientific articles on arXiv’s Computer Vision and Pattern Recognition.

If you’re interested in machine learning but want to switch to something other than computer vision, check out Practical Text Classification With Python and Keras.

Conclusion

Good work! You are now able to find faces in images.

In this tutorial, you have learned how to represent regions in an image with Haar-like features. These features can be calculated very quickly using integral images.

You have learned how AdaBoost finds the best performing Haar-like features from thousands of available features and turns them into a series of weak classifiers.

Finally, you have learned how to create a cascade of weak classifiers that can quickly and reliably distinguish faces from non-faces.

These steps illustrate many important elements of computer vision:

  • Finding useful features
  • Combining them to solve complex problems
  • Balancing between performance and managing computational resources

These ideas apply to object detection in general and will help you solve many real-world challenges. Good luck!


[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]



from Planet Python
via read more

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...