I think it just takes a lot of practice.
Some people here say: OOP is modelling real world objects. But that's what they usually tell you at school too, and as I understand from the OP, it really hasn't been that helpful.
When I look at my code I see it overwhelmed with all kinds of objects that have absolutely no real world representations: database mappers, object factories, expression builders, etc. They might sound like real world objects, but they are really nothing like. They are just abstractions that help us to manage the whole complexity of the program.
I think the main hard part of OOP is exactly that. You can't just look at your problem domain, which for example deals with cars and say: I know, I need a Car class! Even if you do need a Car class, this knowledge doesn't help you decide what to really put inside it. Obviously you can't just put all the hundred thousand features that deal with cars inside that one class. So how do you manage it? How do slice it up? What should be the responsibility of the Car class? Who should also know about Car class? These are the hard questions for which no-one but the author of the program himself can really answer. And even the most experienced ones rarely answer all the questions right at the first time.
But I guess there are some general good OOP principles to follow. Keep the coupling between objects as low as possible. Follow the law of demeter. The SOLID principles are good keep in mind. But most importantly: keep it DRY all the way.
Additionally: Don't limit yourself to object-oriented approach. Study functional programming, regular expressions, compiler construction, assembly language, and a as many different higher level languages as you can manage - knowing OOP alone isn't going to make you a good programmer, but studing all those different approaches and tools will allow you to look OOP at more distinct perspectives, allowing deeper understanding of what this OOP-thing really is about.