如何在OpenCV中利用霍夫变换得到的倾斜线获取ROI(矩阵)
Great question! OpenCV doesn’t have a built-in function specifically for extracting ROIs based on arbitrary straight lines (since the standard ROI is always axis-aligned), but you can absolutely build this functionality yourself using basic geometric operations and masking. Here’s how to do it step by step for your scenario of splitting an image along slightly tilted vertical lines from Hough Transform:
Step 1: Convert Hough Lines to Image Boundary Points
First, we need to take the rho and theta values output by the Hough Transform and convert them into actual points where each line intersects the top and bottom edges of your image. This gives us clear endpoints for each tilted vertical line within the image frame.
import cv2 import numpy as np def hough_line_to_image_points(rho, theta, img_shape): h, w = img_shape[:2] a = np.cos(theta) b = np.sin(theta) # Calculate base point on the line x0 = a * rho y0 = b * rho # Find intersection with top edge (y=0) if b != 0: y_top = 0 x_top = int((rho - y_top * b) / a) if a != 0 else int(x0) else: x_top = int(x0) y_top = 0 # Find intersection with bottom edge (y=h-1) if b != 0: y_bottom = h - 1 x_bottom = int((rho - y_bottom * b) / a) if a != 0 else int(x0) else: x_bottom = int(x0) y_bottom = h - 1 # Clamp coordinates to image boundaries x_top = max(0, min(w - 1, x_top)) x_bottom = max(0, min(w - 1, x_bottom)) return (x_top, y_top), (x_bottom, y_bottom)
Step 2: Sort Lines by Horizontal Position
Since you want to split the image between consecutive vertical lines, sort the lines based on their horizontal position (e.g., the x-coordinate of their top intersection point) to ensure we process them left to right.
# Assume `lines` is the output from cv2.HoughLines() # lines shape: (N, 1, 2) where each entry is (rho, theta) points_list = [] for line in lines: rho, theta = line[0] top_point, bottom_point = hough_line_to_image_points(rho, theta, img.shape) points_list.append((top_point, bottom_point)) # Sort lines by the x-coordinate of their top edge intersection points_list.sort(key=lambda x: x[0][0])
Step 3: Create Polygon Masks & Extract Sub-Images
For each pair of consecutive lines (and the image edges), define a quadrilateral region that represents the area between them. Use this shape to create a binary mask, then extract and crop the region to get your sub-images.
sub_images = [] h, w = img.shape[:2] # Start with the left edge of the image as the first boundary prev_top = (0, 0) prev_bottom = (0, h - 1) # Process each line to create segments between previous boundary and current line for curr_top, curr_bottom in points_list: # Define the quadrilateral vertices for the segment polygon_pts = np.array([ prev_top, curr_top, curr_bottom, prev_bottom ], dtype=np.int32) polygon_pts = polygon_pts.reshape((-1, 1, 2)) # Create mask for the segment mask = np.zeros((h, w), dtype=np.uint8) cv2.fillPoly(mask, [polygon_pts], 255) # Extract the segment using the mask segment = cv2.bitwise_and(img, img, mask=mask) # Crop to the minimal bounding rectangle of the polygon x, y, seg_w, seg_h = cv2.boundingRect(polygon_pts) cropped_segment = segment[y:y+seg_h, x:x+seg_w] sub_images.append(cropped_segment) # Update previous boundary to current line prev_top, prev_bottom = curr_top, curr_bottom # Add the final segment from the last line to the right image edge final_top = (w - 1, 0) final_bottom = (w - 1, h - 1) polygon_pts = np.array([ prev_top, final_top, final_bottom, prev_bottom ], dtype=np.int32) polygon_pts = polygon_pts.reshape((-1, 1, 2)) mask = np.zeros((h, w), dtype=np.uint8) cv2.fillPoly(mask, [polygon_pts], 255) segment = cv2.bitwise_and(img, img, mask=mask) x, y, seg_w, seg_h = cv2.boundingRect(polygon_pts) cropped_segment = segment[y:y+seg_h, x:x+seg_w] sub_images.append(cropped_segment) # Now sub_images contains your split A, B, C, etc.
Key Notes & Tips
- Clean Up Hough Lines: Before processing, filter or deduplicate lines from the Hough Transform to avoid overlapping or redundant boundaries. You can use clustering (like k-means) on line parameters to group similar lines.
- Handle Extreme Tilts: If lines are heavily tilted, double-check the intersection calculation to ensure points stay within the image frame.
- Color Images: This code works for both grayscale and color images since
cv2.bitwise_andoperates on all channels automatically. - Non-Rectangular Output: If you want to keep the original polygonal shape instead of cropping to a rectangle, you can skip the bounding rect step and work with the masked image directly.
内容的提问来源于stack exchange,提问作者amatuer

