SA-Kenan/03_Aufnahmeserie/Ledstripe_Alignment.py
2022-05-09 20:30:26 +02:00

236 lines
11 KiB
Python

# 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')