使用Python中OpenCV消除切向畸变,实现照片3D物体尺寸测量
Absolutely—OpenCV is fully capable of correcting tangential distortion in your photos, and we can tie that correction into your goal of measuring the object’s real-world width (given you know its true height). Let’s walk through the process, including considerations for your 145° camera-to-ground angle.
Tangential distortion (caused by lens elements not being perfectly aligned) is handled directly in OpenCV’s camera calibration and undistortion pipeline. Here’s how to do it:
Step 1: Calibrate Your Camera to Get Distortion Coefficients
First, you need to calculate your camera’s intrinsic parameters and distortion coefficients (specifically p1 and p2, which control tangential distortion). The standard method uses a chessboard calibration pattern:
- Capture 10-20 photos of the chessboard from different angles and distances.
- Use OpenCV’s
cv2.calibrateCamera()to compute the intrinsic matrix (mtx) and distortion vector (dist), which includes the tangential termsp1andp2.
Step 2: Undistort Your Image
Once you have the calibration data, apply the correction to your photo. You can use either cv2.undistort() (simple) or cv2.initUndistortRectifyMap() + cv2.remap() (more efficient for large images):
import cv2 import numpy as np # Replace these with your actual calibration results mtx = np.array([[1200, 0, 640], [0, 1200, 360], [0, 0, 1]]) # Example intrinsic matrix dist = np.array([0.1, -0.05, 0.002, 0.001, 0.0]) # Example distortion coefficients (p1=0.002, p2=0.001) # Load your distorted image img = cv2.imread('object_photo.jpg') h, w = img.shape[:2] # Calculate optimal camera matrix to avoid excessive cropping (adjust the 1.0 parameter if needed) new_camera_mtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h)) # Generate undistortion maps for efficient correction map_x, map_y = cv2.initUndistortRectifyMap(mtx, dist, None, new_camera_mtx, (w, h), cv2.CV_32FC1) # Apply the distortion correction undistorted_img = cv2.remap(img, map_x, map_y, cv2.INTER_LINEAR) # Optional: Crop to the valid region (removes black borders from correction) x, y, crop_w, crop_h = roi undistorted_img = undistorted_img[y:y+crop_h, x:x+crop_w] # Save or use the corrected image cv2.imwrite('undistorted_object.jpg', undistorted_img)
Your camera is tilted upward at 145° relative to the ground, which means the object’s projection in the photo has perspective distortion (separate from lens distortion). To get an accurate width measurement:
- After correcting lens distortion, perform a perspective transform to "flatten" the object’s plane into an orthographic (front-on) view.
- Use the known real height of the object to set the measurement scale:
- In the undistorted image, mark the top and bottom of the object to get its pixel height.
- Calculate the scale factor:
real_height / pixel_height(this gives you real-world length per pixel). - Select 4 reference points on the object’s plane (e.g., its four corners) and warp them to a rectangle that matches the object’s known height-to-width ratio (or a rectangle where the height corresponds to the real height in pixels).
Here’s a quick snippet for the perspective transform:
# Example: 4 points from undistorted image (object corners, adjust to your actual coordinates) src_points = np.float32([[100, 200], [500, 200], [500, 800], [100, 800]]) # Corresponding points in the orthographic view (height matches real scale) real_height = 1.5 # Your object's real height in meters/feet pixel_height = 600 # Measured pixel height in undistorted image scale_factor = real_height / pixel_height real_height_pixels = 600 # Keep same as measured to maintain scale real_width_pixels = int(real_height_pixels * (estimated_width_ratio)) # Or use your target ratio dst_points = np.float32([[0,0], [real_width_pixels,0], [real_width_pixels, real_height_pixels], [0, real_height_pixels]]) # Compute perspective transform matrix perspective_mtx = cv2.getPerspectiveTransform(src_points, dst_points) # Apply the transform to get orthographic view ortho_img = cv2.warpPerspective(undistorted_img, perspective_mtx, (real_width_pixels, real_height_pixels)) # Now measure the width in ortho_img and multiply by scale factor to get real-world width measured_pixel_width = 400 # Example measurement real_width = measured_pixel_width * scale_factor
- Calibrate carefully: Use a high-quality chessboard, capture photos from diverse angles, and ensure the pattern is well-lit to minimize calibration errors.
- Avoid approximate parameters: If you can’t calibrate, don’t guess intrinsic parameters—use EXIF data (if available) or tools that estimate camera specs, but manual calibration is always more reliable.
- Pick precise reference points: When marking the object’s edges or corners, zoom in on the image to get pixel-perfect coordinates.
内容的提问来源于stack exchange,提问作者user3647894




