Low level classes are the simple workers that perform actions, while high level classes are the management class that orchestrate the low level classes.
For example, if you have a class that reads bytes from a file and a class that calculates the CRC of bytes, they are low level classes because each performs an action. If you have a class that uses those two classes to calculate the CRC of a file it's a high level class, because it operates the other classes to accomplish a bigger task.
DiP says that the high level class should not depend directly on the low level classes, but rather get objects of those classes(or factory objects that create them) injected into it, and depend on more generic interfaces - for example, an interface for classes that read bytes and an interface for classes that aggregate bytes. That the higher level class, instead of just doing CRC on files, it could also do MD5 on URLs or any other type of aggregation on any other type of data source.
Keep in mind there are more than just two level. The high level class from the example can be a low level component for an even higher level class, that performs a more complex task.
Another thing to keep in mind is that like any other rule, DiP should not be followed blindly. I've explained in another answer that some low level classes are too small to be decouple-worthy. Also, at some point you'll have to refer low level classes directly from high level classes. High level classes that get low level objects injected into them - who does the injection? Even higher level classes! That means that in some points high level classes have to use low level classes directly. Your main method is the highest there is, and you can't inject anything into it. That doesn't mean you should do all the injection in the main method - deciding where to choose the concrete low level classes is part of the design process.