# Creation Date: 10.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. # Update: This script is designed to take image series with different camera parameters # Update-Comment: # To-DO: import serial 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 # Comment for Measurement-Log: CAM_NR = "04" # CAM:01,02,03,04 COMMENT = "" # Set Parameters for series with variable shutterspeeds # Uncomment/Comment needed code parts for shutter speed lists: #START_SHUTTER_SPEED = 50 # microseconds. 0=auto #END_SHUTTER_SPEED = 100 # microseconds #STEP_SHUTTER_SPEED = 25 # microseconds # shutter_speeds_add = [47, 66, 85, 104] # microseconds. shutter speeds to additionally add shutter_speeds_add = [50] # microseconds. shutter speeds to additionally add # from investigations: ss < 30 are all darker, but the darkness is the same. e.g: ss=5,10,15,20,25 are all the same brightness=Shutter_speed # with ss <5 µs (because < 20 µs) one can request the minimum posisble shutter speed # it was found, that ss is adjustable in 20 µs-steps from 30 µs ongoing: [10 µs, 30 µs, 50 µs] in this range # retrieved ss: 9, 28, 47, 66, 85, 104 µs shutter_speeds = list() #for ss in range(START_SHUTTER_SPEED, END_SHUTTER_SPEED+STEP_SHUTTER_SPEED, STEP_SHUTTER_SPEED): # shutter_speeds.append(ss) #shutter_speeds = shutter_speeds + shutter_speeds_add # concatenate lists shutter_speeds = shutter_speeds_add shutter_speeds.sort() # sort list # camera_resolutions = [(192, 144), (416,320), (640,480), (960,720), (1280,960), (1648,1232)] camera_resolutions = [(192, 144)] iso_values = [320] # Define camera settings if CAM_NR == "03": SENSOR_MODE = 4 # corresponding sensor mode to resolution OUTPUT_RESOLUTION = (416, 320) # (1640x1232)/4=(410,308) # Camera informations for log CAM_DESCRIPTION = "Raspberry Pi Camera Module V2" CAM_EAN = "506021437024020" elif CAM_NR == "04": SENSOR_MODE = 4 # corresponding sensor mode to resolution # Camera informations for log CAM_DESCRIPTION = "Raspberry Pi NoIR Camera Module V2" CAM_EAN = "0640522710898" elif CAM_NR == ("01"): SENSOR_MODE = 4 # corresponding sensor mode to resolution --> gibt es sowas für camera 1? Ja gleicher Sensor wie Raspberry Pi V1 sensor! # Camera informations for log CAM_DESCRIPTION = "RPI-SPYCAM" CAM_EAN = "4251266701743 " elif CAM_NR == ("02"): SENSOR_MODE = 4 # corresponding sensor mode to resolution --> gibt es sowas für camera 2? --> Ja gleicher Sensor wie Raspberry Pi V1 sensor! # Camera informations for log CAM_DESCRIPTION = "RB-Camera_JT" CAM_EAN = "4250236815909" 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) AWB_GAINS = (1.395, 1.15) # White Balance Gains to have colours read correctly: (red, blue). Int, floar or fraction are valid. BRIGHTNESS = 25 # sets the brightness setting of the camera. default is 50. [0-100] #the brighter, the brighter the LEDs and the higher the RGB values and vice versa! CONTRAST = 100 # sets the contrast setting of the camera. The default value is 0. [-100 ... 100] ISO = 320 # ISO value EXPOSURE_MODE = 'off' FRAMERATE = 25 # 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 # Dictionary for color patterns # r: red, g: green, b: blue, y: yellow, m: magenta, c: cyan dict_color_pattern = { "01": "rgb", "02": "rgy", "03": "rgm", "04": "rgc", "05": "rby", "06": "rbm", "07": "rbc", "08": "rym", "09": "ryc", "10": "rmc", "11": "gby", "12": "gbm", "13": "gbc", "14": "gym", "15": "gyc", "16": "gmc", "17": "bym", "18": "byc", "19": "bmc", "20": "ymc", } # Define Funcions def take_image_picamera_opencv(shutter_speed, iso, resolution, led_rgb_value): colour_string = led_rgb_value color_substring_list = [str(x).zfill(2) for x in range(1,21)] # string list to check for color pattern # 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 = 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 # Iso must be set prior fixing the gains (prior setting exposure_mode to off) camera.shutter_speed = shutter_speed # it was found that, you have to set the right shutter speed at the first initalisation of the current runtime of the program. # The gains (analog, digital) will adjust to this set up. # After the gains are fixed, they will never change! even if you change the shutter speed during the runtime. # To get consistent brightness values, set the right shutter speed at initalisation once. time.sleep(SLEEP_TIME) # wait for iso gains and digital_gain and analog_gain to settle before fixing the gains with exposure_mode = off # digital_gain: The value represents the digital gain the camera applies after conversion of the sensor’s analog output. # analog_gain: The value represents the analog gain of the sensor prior to digital conversion. # digital and analog gain can not be set from the user. camera.exposure_mode = EXPOSURE_MODE # exposure_mode value 'off' overrides the ISO setting. # For example, 'off' fixes analog_gain and digital_gain entirely, # preventing this property from adjusting them when set. time.sleep(1) camera.brightness = BRIGHTNESS camera.contrast = CONTRAST # camera.start_preview() time.sleep(SLEEP_TIME) # Camera warm-up time to apply settings exposure_speed = camera.exposure_speed # settings have to be applied before retrieving the right exposure_speed # cv.namedWindow("Current Frame", cv.WINDOW_NORMAL) 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 #display_image_with_text(image, shutter_speed, framenumber) # show the frame framenumber_to_save = 15 # save frame 15 (no particular reason for frame 15) if framenumber == framenumber_to_save: # save desired frame now = datetime.now(); d1 = now.strftime("%Y-%m-%d %H-%M-%S") print(f"Take picture! iso: {iso} shutter speed: {shutter_speed} µs") if "-" in colour_string: cv.imwrite(f"{path_saveFolder}/RGB {colour_string}_ss{shutter_speed}_es{exposure_speed}_iso{iso}_b{BRIGHTNESS}_c{CONTRAST}_res{resolution[0]}x{resolution[1]}_Date {d1}.png", image) elif any(substring in colour_string for substring in color_substring_list): cv.imwrite(f"{path_saveFolder}/cp {colour_string}-{dict_color_pattern[colour_string]}_ss{shutter_speed}_es{exposure_speed}_iso{iso}_b{BRIGHTNESS}_c{CONTRAST}_res{resolution[0]}x{resolution[1]}_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. # if cv.waitKey(1) & 0xff == ord('q'): # break def take_image_series_onecolourchannel_per_led(led_rgb_value): """Take image series in one specified colour.""" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) def take_image_series_rgb(brightness): """Take image series. One colour per series.""" t1 = time.perf_counter() print(f'switchting to red') led_rgb_value = f"{brightness}-000-000" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) print('switchting to green') led_rgb_value = f"000-{brightness}-000" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) print('switchting to blue') led_rgb_value = f"000-000-{brightness}" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) t2 = time.perf_counter() elapsed_time = round((t2-t1)/60,2) print(f'series_rgb finished in {elapsed_time} min') def take_image_series_ymc(brightness): """Take image series. One colour per series.""" t1 = time.perf_counter() print(f'switchting to yellow') led_rgb_value = f"{brightness}-{brightness}-000" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) print('switchting to magenta') led_rgb_value = f"{brightness}-000-{brightness}" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) print('switchting to cyan') led_rgb_value = f"000-{brightness}-{brightness}" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, led_rgb_value) t2 = time.perf_counter() elapsed_time = round((t2-t1)/60,2) print(f'series_rgb finished in {elapsed_time} min') def take_image_series_twocolourchannels_per_led(brightness): """Take image series. Two colours per series.""" # All posibilities with R G B: RG, RB, GB print(f'switchting to red and green') led_rgb_value = f"{brightness}-{brightness}-000" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for ss in range(START_SHUTTER_SPEED, END_SHUTTER_SPEED+STEP_SHUTTER_SPEED, STEP_SHUTTER_SPEED): take_image_picamera_opencv(ss, led_rgb_value) print('switchting to red and blue') led_rgb_value = f"{brightness}-000-{brightness}" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for ss in range(START_SHUTTER_SPEED, END_SHUTTER_SPEED+STEP_SHUTTER_SPEED, STEP_SHUTTER_SPEED): take_image_picamera_opencv(ss, led_rgb_value) print('switchting to green and blue') led_rgb_value = f"000-{brightness}-{brightness}" s.write(str.encode(led_rgb_value)); response = s.readline(); print(response) for ss in range(START_SHUTTER_SPEED, END_SHUTTER_SPEED+STEP_SHUTTER_SPEED, STEP_SHUTTER_SPEED): take_image_picamera_opencv(ss, led_rgb_value) def takeimage_all_color_patterns(): """Take images of all 20 color patterns including orientation """ "The brightness is hard coded to 255 in the Arduino" t1 = time.perf_counter() print(f'take images for all 20 color patterns') for number_of_color_pattern in range(1,21): number_of_color_pattern = str(number_of_color_pattern).zfill(2) print(f"color pattern no: {number_of_color_pattern}: {dict_color_pattern[number_of_color_pattern]}") s.write(str.encode(f"color_pattern_{number_of_color_pattern}")) for i, resolution in enumerate(camera_resolutions): print(f'resolution {i+1}/{len(camera_resolutions)}: {resolution}') for ss in shutter_speeds: for iso in iso_values: take_image_picamera_opencv(ss, iso, resolution, number_of_color_pattern) t2 = time.perf_counter() elapsed_time = round((t2-t1)/60,2) print(f'series_rgb finished in {elapsed_time} min') def display_image_with_text(img, shutter_speed, framenumber): 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 # set position in (x,y)-coordinated from top left corner. Bottom-left corner of the text string in the image. pos_1 = (int(frame_width/4), text_start_position_Y) # start text from 1/4 of image width pos_2 = (int(frame_width/4), text_start_position_Y+text_linespacing) # start text from 1/4 of image width # define text to display text_line_1 = f"Shutterspeed: {shutter_speed} us" text_line_2 = f"Frame: {framenumber}" # 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) cv.imshow("Current Frame", img) # display the image # 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"/Solarradiation_"+d1 path_saveFolder = path_cwd+r"/series_"+d1 try: os.mkdir(path_saveFolder) lines = [f"CAMERA NR: {CAM_NR}", f"CAMERA DESCRIPTION: {CAM_DESCRIPTION}", f"CAMERA EAN: {CAM_EAN}", f"\n#Camera settings:", f"SENSOR MODE: {SENSOR_MODE}", f"FRAMERATE: {FRAMERATE} # frames per second", f"AWB_MODE: {AWB_MODE}", f"AWB_GAINS (red, blue): {AWB_GAINS}", f"Brightness: {BRIGHTNESS}", f"Contrast: {CONTRAST}", f"EXPOSURE_MODE: {EXPOSURE_MODE}", f"\nCOMMENT: {COMMENT}"] with open(os.path.join(path_saveFolder, "log.txt"), "w") as f: f.write("\n".join(lines)) except OSError: print("Error! Ending script. Try it again in 1 minute") quit() # Turn on LEDs s = serial.Serial("/dev/ttyACM0", 9600) # Name of USB-Port may vary (here: ACM0) time.sleep(5) # der Arduino resettet nach einer Seriellen Verbindung, daher muss kurz gewartet werden # start capture series for different shutter speeds print('start caputure series...') # s.write(str.encode("000-255-000")); response = s.readline(); print(response) # take_image_picamera_opencv(shutter_speed=200, led_rgb_value="000-255-000") # take image series for two colour channels per led # for brgns in range(50,260,50): # brgns=str(brgns).zfill(3) # take_image_series_twocolourchannels_per_led(brgns) #Take Image Series for every color in given brightness # take_image_series_twocolourchannels_per_led(255) #Take Image Series for every color in given brightness # # take image series for white colour # for brgns in range(50,260,50): # brgns=f"{brgns}".zfill(3) # ledcolour=f"{brgns}-{brgns}-{brgns}" # take_image_series_onecolourchannel_per_led(ledcolour) # take_image_series_onecolourchannel_per_led("255-255-255") # -------------------------------------------------------------------------------------------------------------------------------------------- # # 03.02.2022: Take images with multiple shutter speeds but in brightness 255 for determining colour falsification to the edges of the image # take_image_series_rgb(255) # take_image_series_ymc(255) # take_image_series_onecolourchannel_per_led("255-255-255") # -------------------------------------------------------------------------------------------------------------------------------------------- # # 26.02.2022: Take images with multiple shutter speeds and brightness for investigating the influence of the solar radiation on the images # # take image series for rgb # for brgns in range(50,260,50): # brgns=str(brgns).zfill(3) # take_image_series_ymc(brgns) #Take Image Series for every color in given brightness # take_image_series_ymc(255) #Take Image Series for every color in given brightness # # take image series for ymc # for brgns in range(50,260,50): # brgns=str(brgns).zfill(3) # take_image_series_rgb(brgns) #Take Image Series for every color in given brightness # take_image_series_rgb(255) #Take Image Series for every color in given brightness # # take image series for white colour # for brgns in range(50,260,50): # brgns=f"{brgns}".zfill(3) # ledcolour=f"{brgns}-{brgns}-{brgns}" # take_image_series_onecolourchannel_per_led(ledcolour) # take_image_series_onecolourchannel_per_led("255-255-255") # -------------------------------------------------------------------------------------------------------------------------------------------- # 10.04.2022: Take images with multiple shutter speeds for investigating the influence of the solar radiation on the images # take image series for rgb take_image_series_rgb(255) #Take Image Series for every color in given brightness # take image series for ymc take_image_series_ymc(255) #Take Image Series for every color in given brightness # take image series for white colour take_image_series_onecolourchannel_per_led("255-255-255") # -------------------------------------------------------------------------------------------------------------------------------------------- # 07.03.2022: Take images of all 20 color patterns with birghtness 255 takeimage_all_color_patterns() # -------------------------------------------------------------------------------------------------------------------------------------------- # End Script # Turn off LEDs s.write(str.encode('000-000-000')); response = s.readline(); print(response) s.close() #close serial port cv.destroyAllWindows() t1 = round(time.perf_counter()/60,2) print(f'Script finished in {t1} min')