# Creation Date: 14.01.2022 # Author: Kenan Gömek # This script takes pictures with Picameras VideoPort like it will be used to work with OpenCV and saves it with OpenCV to have the real use case pictures. # This script is designed for aligning the LED-Stripe horizontally to the image sensor with LEDs off # Use: # 1. turn on the LEDs to e.g. 005-000-000 manually via bash or similar # 2. execute this script # 3. adjust shutter speed if desired with x,c,b,n,m (program starts with max shutter speed for selected frame rate) # 4. align LED strip e.g. to the upper blue line and first led to the left edge of the image # 5. take image of alignment with 'i' # 6. end program with 'q' import cv2 as cv import picamera from picamera.array import PiRGBArray from fractions import Fraction import time from datetime import datetime import os import numpy as np # Define camera settings # divide origin resoluton by a number, to have the origin aspect ratio # RESOLUTION = (3280, 2464) # Max Photo-Resolution CAM03 and CAM04 # no image with PiCamera Videoport at this Resolution.. Probably GPU Memory and CPU issues. # RESOLUTION = (1640,1232) # 2nd best Resolution for CAM03 and CAM04 with FUll FOV (2x2 binning) # Mode 4 SENSOR_MODE = 4 # corresponding sensor mode to resolution OUTPUT_RESOLUTION = (416, 320) # (1640x1232)/4=(410,308) # (410,308) is being upscaled to (416,320) from ISP (warning in bash), but image will have still (410,308) pixels. # OUTPUT_RESOLUTION = (820, 616) # (1640x1232)/2=(820,616) # bash: frame size rounded up from 820x616 to 832x624 AWB_MODE = 'off' # Auto white balance mode AWB_GAINS = (Fraction(485, 256), Fraction(397, 256)) # White Balance Gains to have colours read correctly: (red, blue) ISO = 100 # ISO value EXPOSURE_MODE = 'off' FRAMERATE = 10 # frames per second. 40 fps is max for sensor mode 4 SLEEP_TIME = 2 # Time for sleep-mode for the camera in seconds. My default: 2 s # Define Funcions def take_image_picamera_opencv(shutter_speed): # Initialise Camera with picamera.PiCamera() as camera: with PiRGBArray(camera) as output: # Set camera settings camera.sensor_mode = SENSOR_MODE # force camera into desired sensor mode camera.resolution = OUTPUT_RESOLUTION # frame will be resized from GPU to this resolution. No CPU usage! camera.framerate = FRAMERATE camera.awb_mode = AWB_MODE camera.awb_gains = AWB_GAINS camera.iso = ISO camera.shutter_speed = shutter_speed camera.exposure_mode = EXPOSURE_MODE time.sleep(SLEEP_TIME) # Camera warm-up time to apply settings # camera.start_preview() # show camera preview through PiCamera interface # camera.annotate_frame_num=True # Controls whether the current frame number is drawn as an annotation. for frameidx, frame in enumerate(camera.capture_continuous(output, format='bgr', use_video_port=True)): framenumber = frameidx+1 # frameidx starts with 0, framenumber with 1 image = frame.array # raw NumPy array without JPEG encoding camera_exposure_speed = camera.exposure_speed # Retrieves the current shutter speed of the camera. # cv.imshow("Current Frame", image) # display the image without text img = alignment_procedure(image, shutter_speed, framenumber, camera_exposure_speed) # show the frame framenumber_to_save = 7000 # frame 15 (no particular reason for frame 15) trigger_save_frame = 'no' # trigger for saving the frame if framenumber == framenumber_to_save and trigger_save_frame=='yes': # save desired frame now = datetime.now(); d1 = now.strftime("%Y-%m-%d %H-%M-%S.%f")[:-3] print(f"Take picture! framenumber: {framenumber} shutter speed: {shutter_speed} µs") cv.imwrite(f"{path_saveFolder}/ss{shutter_speed}_Date {d1}.png", image) break # break from the loop, because we took the image we wanted output.truncate(0) # clear the stream for next frame # Only uncomment following code if you display the image. No errors if not commented, but higher fps if commented. # if q is pressed, break from loop. pressed_key = cv.waitKey(1) & 0xff if pressed_key == ord('q'): break elif pressed_key == ord('i'): # Take image from manipulated image if i is pressed now = datetime.now(); d1 = now.strftime("%Y-%m-%d %H-%M-%S.%f")[:-3] cv.imwrite(f"{path_saveFolder}/Date {d1}.png", img) print('took image!') elif pressed_key == ord('b'): # increase shutterspeed by 50 shutter_speed = round(shutter_speed+50) camera.shutter_speed = shutter_speed elif pressed_key == ord('n'): # increase shutterspeed by 500 shutter_speed = round(shutter_speed+500) elif pressed_key == ord('m'): # max shutterspeed shutter_speed = round(1/FRAMERATE*1e6) camera.shutter_speed = shutter_speed elif pressed_key == ord('x'): # decrease shutterspeed by 500 shutter_speed = round(shutter_speed-500) camera.shutter_speed = shutter_speed elif pressed_key == ord('c'): # decrease shutterspeed by 50 shutter_speed = round(shutter_speed-50) camera.shutter_speed = shutter_speed elif pressed_key == ord('o'): # set shutter speed to 0 shutter_speed = 0 camera.shutter_speed = shutter_speed def display_image_with_text(img, shutter_speed, framenumber, camera_exposure_speed): img = img.copy() # make copy of image and do not modify the original image font = cv.FONT_HERSHEY_SIMPLEX # font fontScale = 1 # fontScale color = (255, 255, 255) # Font colour in BGR thickness = 1 # Line thickness in px # set text position frame_width = int(img.shape[1]) frame_height = int(img.shape[0]) text_start_position_Y = int(round(frame_height*0.12)) # start position of text in pixels 12 % of frame height text_linespacing = 50 # line spacing between two strings in pixels # text_start_position_X = int(frame_width/4) # start text from 1/4 of image width text_start_position_X = int(0) # start text from left edge of image # set position in (x,y)-coordinated from top left corner. Bottom-left corner of the text string in the image. pos_1 = (text_start_position_X, text_start_position_Y) # start text from 1/4 of image width pos_2 = (text_start_position_X, text_start_position_Y+text_linespacing) # start text from 1/4 of image width pos_3 = (text_start_position_X, text_start_position_Y+2*text_linespacing) # start text from 1/4 of image width # define text to display text_line_1 = f"set shttr-spd: {shutter_speed} us" text_line_3 = f"Frame: {framenumber}" text_line_2 = f"ret exp-spd: {camera_exposure_speed} us" # put the text into the image image_text_1 = cv.putText(img, text_line_1, pos_1, font, fontScale, color, thickness, cv.LINE_AA) image_text_2 = cv.putText(img, text_line_2, pos_2, font, fontScale, color, thickness, cv.LINE_AA) image_text_3 = cv.putText(img, text_line_3, pos_3, font, fontScale, color, thickness, cv.LINE_AA) cv.imshow("Current Frame", img) # display the image def alignment_procedure(img, shutter_speed, framenumber, camera_exposure_speed): img = img.copy() # make copy of image and do not modify the original image font = cv.FONT_HERSHEY_SIMPLEX # font fontScale = 1 # fontScale color = (255, 255, 255) # Font colour in BGR thickness = 1 # Line thickness in px # set text position frame_width = int(img.shape[1]) frame_height = int(img.shape[0]) text_start_position_Y = int(round(frame_height*0.12)) # start position of text in pixels 12 % of frame height text_linespacing = 50 # line spacing between two strings in pixels # text_start_position_X = int(frame_width/4) # start text from 1/4 of image width text_start_position_X = int(0) # start text from left edge of image # set position in (x,y)-coordinated from top left corner. Bottom-left corner of the text string in the image. pos_1 = (text_start_position_X, text_start_position_Y) # start text from 1/4 of image width pos_2 = (text_start_position_X, text_start_position_Y+text_linespacing) # start text from 1/4 of image width pos_3 = (text_start_position_X, text_start_position_Y+2*text_linespacing) # start text from 1/4 of image width # define text to display text_line_1 = f"set shttr-spd: {shutter_speed} us" text_line_3 = f"Frame: {framenumber}" text_line_2 = f"ret exp-spd: {camera_exposure_speed} us" # put the text into the image image_text_1 = cv.putText(img, text_line_1, pos_1, font, fontScale, color, thickness, cv.LINE_AA) image_text_2 = cv.putText(img, text_line_2, pos_2, font, fontScale, color, thickness, cv.LINE_AA) image_text_3 = cv.putText(img, text_line_3, pos_3, font, fontScale, color, thickness, cv.LINE_AA) # draw lines into image alignment_line_thickness = 1 # thickness of the alignment line in pixels alignment_line_offset = 21 # offset of the alignment line from the center frame_center = round(frame_height/2) # center of the frame offset_center = frame_center + 70 # offset of the center for e.g. have the alignment lines more in the bottom part of the image alignment_row_start = offset_center-alignment_line_offset alignment_row_end = offset_center+alignment_line_offset img[offset_center, :, :] = [255,255,255] # bgr format img[alignment_row_start-alignment_line_thickness:alignment_row_start, :, :] = [255,0,0] # bgr format img[alignment_row_end:alignment_row_end+alignment_line_thickness, :, :] = [0,0,255] # bgr format cv.imshow("Current Frame", img) # display the image return img # Start Script # Create folder for saving the captured pictures now = datetime.now(); d1 = now.strftime("%Y-%m-%d %H-%M") path_cwd = os.getcwd() path_saveFolder = path_cwd+r"/Ledstripe_alignment_"+d1 try: os.mkdir(path_saveFolder) except OSError: print("Error! Ending script. Try it again in 1 minute") quit() # start capture series for different shutter speeds print('start caputure series...') # take_image_picamera_opencv(shutter_speed=2000000) #Can see something at normal light conditions take_image_picamera_opencv(shutter_speed=round(1/FRAMERATE*1e6)) # max shutter-speed depending on fps: 1/2 fps = 500 000 µs # End Script cv.destroyAllWindows() print('Script finished')