1+ import cv2
2+ import numpy as np
3+
4+ # Initialize global variables
5+ points = []
6+
7+ def order_points (pts ):
8+ # Sort the points based on their x-coordinates
9+ x_sorted = pts [np .argsort (pts [:, 0 ]), :]
10+
11+ # Grab the left-most and right-most points from the sorted
12+ # x-coordinate points
13+ left_most = x_sorted [:2 , :]
14+ right_most = x_sorted [2 :, :]
15+
16+ # Now, sort the left-most coordinates according to their
17+ # y-coordinates so we can grab the top-left and bottom-left
18+ # points, respectively
19+ left_most = left_most [np .argsort (left_most [:, 1 ]), :]
20+ (tl , bl ) = left_most
21+
22+ # Now, sort the right-most coordinates according to their
23+ # y-coordinates so we can grab the top-right and bottom-right
24+ # points, respectively
25+ right_most = right_most [np .argsort (right_most [:, 1 ]), :]
26+ (tr , br ) = right_most
27+
28+ # Return the coordinates in top-left, top-right,
29+ # bottom-right, and bottom-left order
30+ return np .array ([tl , tr , br , bl ], dtype = "float32" )
31+
32+ def mouse_callback (event , x , y , flags , param ):
33+ global points
34+ if event == cv2 .EVENT_LBUTTONDOWN :
35+ if len (points ) < 4 :
36+ points .append ((x , y ))
37+ print (f"Point { len (points )} selected: ({ x } , { y } )" )
38+ cv2 .circle (param ['image' ], (x , y ), 5 , (0 , 255 , 0 ), - 1 )
39+ cv2 .imshow ("Select 4 Points" , param ['image' ])
40+ if len (points ) == 4 :
41+ print ("All points selected. Press any key to proceed." )
42+ cv2 .waitKey (0 )
43+ cv2 .destroyAllWindows ()
44+ elif event == cv2 .EVENT_RBUTTONDOWN :
45+ points = []
46+ print ("Points cleared. Please select 4 points again." )
47+ param ['image' ] = param ['original_image' ].copy ()
48+ cv2 .imshow ("Select 4 Points" , param ['image' ])
49+
50+ def transform_birdseye (image , src_points , dst_size , camera_in ):
51+ try :
52+ if image is None or image .size == 0 :
53+ raise ValueError ("Invalid image data or failed to load image." )
54+
55+ # Order points
56+ src_pts = order_points (np .array (src_points , dtype = "float32" ))
57+
58+ # Define the output size
59+ W , H = dst_size
60+ dst_pts = np .array ([
61+ [0 , 0 ],
62+ [W - 1 , 0 ],
63+ [W - 1 , H - 1 ],
64+ [0 , H - 1 ]
65+ ], dtype = np .float32 )
66+
67+ # Perform undistortion using intrinsics
68+ undistorted_image = cv2 .undistort (image , camera_in , None )
69+
70+ # Compute perspective transform matrix
71+ M = cv2 .getPerspectiveTransform (src_pts , dst_pts )
72+ print ("Perspective Transform Matrix:\n " , M )
73+
74+ # Perform perspective warp
75+ warped = cv2 .warpPerspective (undistorted_image , M , (W , H ))
76+ return warped , M
77+
78+ except Exception as e :
79+ print (f"Error during transformation: { e } " )
80+ return None , None
81+
82+ def main ():
83+ global points
84+ points = [] # Reset points list
85+
86+ # Camera intrinsics
87+ # camera_in = np.array([
88+ # [684.83331299, 0.0, 573.37109375],
89+ # [0.0, 684.60968018, 363.70092773],
90+ # [0.0, 0.0, 1.0]
91+ # ], dtype=np.float32)
92+
93+ camera_in = np .array ([
94+ [1 , 0.0 , 0 ],
95+ [0.0 , 1 , 0 ],
96+ [0.0 , 0.0 , 1.0 ]
97+ ], dtype = np .float32 )
98+
99+ # Load image
100+ # image_path = "/home/aadarshhegde/Documents/GEMstack/data/parking_data-20250312T213928Z-001/parking_data/front_cam97.png"
101+ image_path = "/home/aadarshhegde/Documents/GEMstack/data/parking_data-20250312T213928Z-001/parking_data/camera_fl95.png"
102+ # image_path = '/home/aadarshhegde/Documents/GEMstack/data/parking_others/parking_data-20250312T213928Z-001/parking_data/camera_fr109.png'
103+ image = cv2 .imread (image_path )
104+
105+ if image is None :
106+ print ("Could not load image. Check the path." )
107+ return
108+
109+ # Clone for display
110+ display_image = image .copy ()
111+
112+ # Select points using mouse
113+ print ("Select 4 points for the bird's-eye view. Press 'Esc' to finish." )
114+ cv2 .imshow ("Select 4 Points" , display_image )
115+ cv2 .setMouseCallback ("Select 4 Points" , mouse_callback , {'image' : display_image , 'original_image' : image .copy ()})
116+ cv2 .waitKey (0 )
117+
118+ if len (points ) != 4 :
119+ print ("Error: Please select exactly 4 points." )
120+ return
121+
122+ # Output size (adjust to your needs)
123+ out_width = 800
124+ out_height = 600
125+
126+ # Perform the transformation
127+ warped , M = transform_birdseye (image , points , (out_width , out_height ), camera_in )
128+
129+ if warped is not None :
130+ # Display the results
131+ cv2 .imshow ("Original" , image )
132+ cv2 .imshow ("Bird's-Eye View" , warped )
133+ cv2 .waitKey (0 )
134+ cv2 .destroyAllWindows ()
135+
136+ if __name__ == "__main__" :
137+ main ()
0 commit comments