No, I don't think an Object Oriented controller in such as scenario necessarily needs to be tied to the routing mechanism. You could use Facade or Command patterns to call a controller without it (the controller) ever knowing the details of that call (or, more precisely, without having the controller object know more than it needs to about the call).
IMHO the advantage of passing for procedural controllers to Object Oriented ones doesn't necessarily lie just in how well it can be isolated from the rooting part, but more in how you can more easily reuse and organize those OO controllers as opposed to procedural ones. What's the rough estimate of the percentage of similar behavior that all your procedural controllers have between them? You could put all that into one "base" OO controller, and then re-use it via inheritance or composition (preferably, the latter) to pass that common behavior to all your other controllers, without having to duplicate it each time in the code (or cross-importing the procedural scripts one in-to the other).
As per the comment below, here's an example inspired from Spring Framework's old (v2) MVC module:
- one or more router objects. The router object(s) are configured with URL patterns and the corresponding controller objects for each pattern. This way, when the router is hit by a request (which matches a certain URL pattern), it will create an object with that request's parameters (here you can but as many or as few details on the actual request as you like) and call the corresponding controller object passing him the request object
This way you have your controller not only isolated from the low level details of the request, but from the rooter as well (they communicate via an intermediate requet object, neither cares how it was produced or consumed, respectively)
multiple controller objects which map to one or more URL patterns each. Usually you'll create an interface for the controller and that's the only thing the router will know about each controller. Then you implement that interface into actual controllers according to each business need. Here you'll take the most advantage of OO, as you can encapsulate common behavior into an Abstract controller class which you can then extend for certain controllers, etc
finally you'll have one or more view resolver objects. These will be used by the controllers to know what view to show once they do their processing and create a model object. The view resolvers simply associate either URL pattern(s) or controller(s) to views.
as said earlier the controller will produce a model object. This guy will contain all the necessary data so that the view can update itself for the given action/workflow
make sure to keep your model, view and controller objects cleanly separated (as much as possible). The controller should only get the necessary request data, and construct the model accordingly. If going from request data to model is complicated, make separate service objects that deal with it and just have them return th model to the controller so that it can pass it to the view (and notify it if necessary). The controller only deals with getting input data and passing the model to the view. The model should be super dumb, no business logic or anything like that in it. It should just hold the data for the view. The view itself should only be concerned with presentation, i.e. with formatting the data for the user, not with business logic or other heavy treatment of the model data (the model should contain the final data to display).