如何在OpenCV Python二维码扫描程序中限制扫描区域(仿Android二维码扫描框效果)
Restrict QR Code Scanning to a Specific Region (Custom Scan Frame)
I totally get what you're looking for—having a dedicated scan frame not only makes the UI more intuitive but also cuts down on unnecessary processing by focusing only on the area that matters. Let's tweak your existing code to add this feature, matching the styled scan frame you referenced.
Key Changes We'll Implement
- Define a centered, adjustable scan region (square by default)
- Draw a polished scan frame with corner markers and an animated scan line
- Crop the video feed to only the scan region before running QR detection
- Map detected QR code coordinates back to the original frame for accurate display
Modified Full Code
import cv2 import numpy as np import sys import pyzbar.pyzbar as pyzbar cap = cv2.VideoCapture(0) hasFrame, frame = cap.read() if not hasFrame: print("Could not access camera!") sys.exit() # Define scan region parameters (adjust these to fit your needs) frame_width = frame.shape[1] frame_height = frame.shape[0] scan_size = min(frame_width, frame_height) // 2 # Size of the square scan frame scan_x = (frame_width - scan_size) // 2 scan_y = (frame_height - scan_size) // 2 scan_w = scan_size scan_h = scan_size # Initialize video writer vid_writer = cv2.VideoWriter('output.avi', cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width, frame_height)) # For animated scan line effect scan_line_y = scan_y scan_line_direction = 1 # 1 = move down, -1 = move up # Display barcode/QR code location (adjusted for scan region coordinates) def display(im, decodedObjects, scan_x, scan_y): for decodedObject in decodedObjects: points = decodedObject.polygon # Handle non-quad shapes with convex hull if len(points) > 4 : hull = cv2.convexHull(np.array([point for point in points], dtype=np.float32)) hull = list(map(tuple, np.squeeze(hull))) else : hull = points # Adjust coordinates from cropped region back to original frame adjusted_hull = [(x + scan_x, y + scan_y) for (x, y) in hull] # Draw the convex hull n = len(adjusted_hull) for j in range(0, n): cv2.line(im, adjusted_hull[j], adjusted_hull[(j+1) % n], (255, 0, 0), 3) # Initialize OpenCV QR detector qrDecoder = cv2.QRCodeDetector() while True: hasFrame, inputImage = cap.read() if not hasFrame: break # Draw scan frame UI elements # Outer border cv2.rectangle(inputImage, (scan_x-2, scan_y-2), (scan_x+scan_w+2, scan_y+scan_h+2), (0, 255, 0), 2) # Optional: Darken areas outside scan region to focus attention mask = np.zeros_like(inputImage) mask[scan_y:scan_y+scan_h, scan_x:scan_x+scan_w] = inputImage[scan_y:scan_y+scan_h, scan_x:scan_x+scan_w] inputImage = cv2.addWeighted(inputImage, 0.5, mask, 0.5, 0) # Corner markers for the scan frame corner_length = 20 cv2.line(inputImage, (scan_x, scan_y), (scan_x + corner_length, scan_y), (0, 255, 0), 3) cv2.line(inputImage, (scan_x, scan_y), (scan_x, scan_y + corner_length), (0, 255, 0), 3) cv2.line(inputImage, (scan_x+scan_w, scan_y), (scan_x+scan_w - corner_length, scan_y), (0, 255, 0), 3) cv2.line(inputImage, (scan_x+scan_w, scan_y), (scan_x+scan_w, scan_y + corner_length), (0, 255, 0), 3) cv2.line(inputImage, (scan_x, scan_y+scan_h), (scan_x + corner_length, scan_y+scan_h), (0, 255, 0), 3) cv2.line(inputImage, (scan_x, scan_y+scan_h), (scan_x, scan_y+scan_h - corner_length), (0, 255, 0), 3) cv2.line(inputImage, (scan_x+scan_w, scan_y+scan_h), (scan_x+scan_w - corner_length, scan_y+scan_h), (0, 255, 0), 3) cv2.line(inputImage, (scan_x+scan_w, scan_y+scan_h), (scan_x+scan_w, scan_y+scan_h - corner_length), (0, 255, 0), 3) # Animate the scan line cv2.line(inputImage, (scan_x, scan_line_y), (scan_x+scan_w, scan_line_y), (0, 255, 0), 2) scan_line_y += scan_line_direction if scan_line_y >= scan_y + scan_h or scan_line_y <= scan_y: scan_line_direction *= -1 # Crop to the scan region for QR detection scan_region = inputImage[scan_y:scan_y+scan_h, scan_x:scan_x+scan_w] # Run detection only on the cropped scan region decodedObjects = pyzbar.decode(scan_region) zbarData = decodedObjects[0].data.decode('utf-8') if decodedObjects else '' opencvData, bbox, rectifiedImage = qrDecoder.detectAndDecode(scan_region) # Display detection results if zbarData: cv2.putText(inputImage, f"ZBAR : {zbarData}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA) else: cv2.putText(inputImage, "ZBAR : QR Code NOT Detected", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA) if opencvData: cv2.putText(inputImage, f"OpenCV: {opencvData}", (10, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA) else: cv2.putText(inputImage, "OpenCV: QR Code NOT Detected", (10, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, cv2.LINE_AA) # Draw detected QR code borders (adjusted to original frame) display(inputImage, decodedObjects, scan_x, scan_y) # Draw OpenCV's detected QR box if present if bbox is not None: bbox = bbox + np.array([[scan_x, scan_y]]) n = len(bbox) for j in range(n): cv2.line(inputImage, tuple(bbox[j][0]), tuple(bbox[(j+1)%n][0]), (0, 0, 255), 3) cv2.imshow("Result", inputImage) vid_writer.write(inputImage) k = cv2.waitKey(20) if k == 27: # Press ESC to exit break cv2.destroyAllWindows() vid_writer.release() cap.release()
Breakdown of Key Modifications
- Scan Region Setup:
- We calculate a centered square using the camera's frame dimensions. Adjust
scan_sizeto make the frame larger or smaller as needed.
- We calculate a centered square using the camera's frame dimensions. Adjust
- Polished UI:
- Added corner markers and an animated scan line to match the example you referenced.
- Optional darkening of areas outside the scan region helps users focus on the target area.
- Cropped Detection:
- Only the scan region is passed to QR detection functions, reducing processing overhead and ensuring only codes in the frame are recognized.
- Coordinate Adjustment:
- Detected QR code coordinates are mapped back to the original frame so the bounding boxes appear in the correct position.
内容的提问来源于stack exchange,提问作者alex-uarent-alex
相关产品推荐
相关产品推荐

