PyObjC Vision Framework
pyobjc-framework-vision provides Python wrappers for Apple's Vision framework on macOS. It is part of the PyObjC project, a bidirectional bridge enabling Python scripts to interact with Objective-C libraries, including macOS Cocoa frameworks. The current version is 12.1 and it maintains an active release cadence, typically aligning with macOS SDK updates and Python version support.
Warnings
- breaking PyObjC frequently drops support for older Python versions. PyObjC 12.0 dropped support for Python 3.9, and PyObjC 11.0 dropped Python 3.8. Ensure your Python version is compatible with the PyObjC version you are installing.
- breaking PyObjC 11.1 changed how initializer methods (`init` family) are modeled, now correctly reflecting that they 'steal' a reference to `self` and return a new one, as per clang's ARC documentation. This affects object lifecycle and reference counting.
- gotcha Unlike Objective-C, where sending a message to `nil` (equivalent to Python `None`) is a no-op, attempting to call a method on a Python `None` object (which PyObjC translates from `nil`) will raise an `AttributeError`.
- gotcha PyObjC is a macOS-specific library and will not install or run on other operating systems. The frameworks it wraps (like Vision) are Apple-proprietary.
- gotcha When implementing custom Objective-C subclasses in Python, the Objective-C method names (selectors) containing colons (`:`) are translated to Python method names with underscores (`_`). For example, `doSomething:withSomethingElse:` becomes `doSomething_withSomethingElse_`.
Install
-
pip install pyobjc-framework-vision
Imports
- Vision
import Vision
- NSURL
from Cocoa import NSURL
- NSDictionary
from Foundation import NSDictionary
Quickstart
import os
import Vision
from Foundation import NSURL, NSDictionary
from Cocoa import CIImage # Often found in Quartz, but CIImage is exposed via Cocoa as well for convenience
def recognize_text_in_image(image_path):
if not os.path.exists(image_path):
print(f"Error: Image not found at {image_path}")
return
# Convert Python path to NSURL
input_url = NSURL.fileURLWithPath_(image_path)
# Create CIImage from the URL
input_image = CIImage.imageWithContentsOfURL_(input_url)
if input_image is None:
print(f"Error: Could not create CIImage from {image_path}")
return
# Create a Vision request handler
vision_options = NSDictionary.dictionaryWithDictionary_({})
vision_handler = Vision.VNImageRequestHandler.alloc().initWithCIImage_options_(
input_image, vision_options
)
# Prepare a text recognition request
results = []
def completion_handler(request, error):
if error:
print(f"Vision request error: {error}")
else:
for observation in request.results():
if isinstance(observation, Vision.VNRecognizedTextObservation):
for text_candidate in observation.topCandidates_(1):
results.append(text_candidate.string())
text_request = Vision.VNRecognizeTextRequest.alloc().initWithCompletionHandler_(
completion_handler
)
# Perform the request
error_ptr = None # PyObjC expects None for output pointers that aren't being used for input
success, error = vision_handler.performRequests_error_([text_request], error_ptr)
if not success:
print(f"Failed to perform Vision request: {error}")
return results
# Example usage:
# Create a dummy image file for demonstration
# In a real scenario, replace this with a path to an actual image file.
# For a real image with text, you might create one using Pillow or similar.
dummy_image_path = os.environ.get('VISION_TEST_IMAGE_PATH', 'dummy_image_with_text.png')
if not os.path.exists(dummy_image_path):
print(f"Please set VISION_TEST_IMAGE_PATH or create a file named '{dummy_image_path}' to run this example.")
print("Example: create a simple PNG with some text using an image editor.")
else:
print(f"Analyzing image: {dummy_image_path}")
detected_text = recognize_text_in_image(dummy_image_path)
if detected_text:
print("Detected text:")
for text in detected_text:
print(f"- {text}")
else:
print("No text detected or an error occurred.")