-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathir_cut_picamera2_array.py
141 lines (121 loc) · 5.47 KB
/
ir_cut_picamera2_array.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
######## PiCamera2/OpenCV picture taker for the RPI IR-Cut camera #########
# Author: Petros626
# forked from/oriented on: https://github.com/EdjeElectronics/Image-Dataset-Tools/blob/main/PictureTaker/PictureTaker.py
# Date: 19.04.2023
# Description:
# This program takes pictures (.png format - 95% quality and 0 compression) from a the RPi IR-Cut
# camera and saves them in the specified directory. The default directory is 'images' and the
# default resolution is 1920x1080. Additionally lens undistortion with camera calibration algorithm are
# implemented.
# Example usage to save images in a directory named images at 1920x1080 resolution:
# python3 run_camera_config.py --imgdir=images --res=1920x1080
# This code is based off the Picamera2 library examples at:
# https://github.com/raspberrypi/picamera2/tree/a9f7a7d0bac726ab9b3f366ff461ddd62e885f40/examples
# https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html
# https://betterprogramming.pub/how-to-calibrate-a-camera-using-python-and-opencv-23bab86ca194
from picamera2 import Picamera2
from os import getcwd, path, makedirs
from argparse import ArgumentParser
from keyboard import is_pressed
from termios import tcflush, TCIOFLUSH
from sys import stdin, exit
from libcamera import controls
from json import load
from numpy import array, float64
from cv2 import (
cvtColor, imwrite, COLOR_RGBA2RGB, undistort, imshow, getOptimalNewCameraMatrix, waitKey, destroyAllWindows,
namedWindow, WINDOW_NORMAL, startWindowThread, resizeWindow, moveWindow
)
#### Parser and safety requests #####
# Fetch script arguments
parser = ArgumentParser()
parser.add_argument("--imgdir", help = "Folder where the taken images get saved. If you not specify there will be created one automatically.",
default = "images")
parser.add_argument("--res", help = "Required resolution in WxH. To avoid erros find out about the supported resolutions of your camera model.",
default = "1920x1080")
args = parser.parse_args()
dirname = args.imgdir
# Check if resolution is specified correctly
if not "x" in args.res:
print("Specify resolution with x as WxH. (Example: 1920x1080).")
exit()
imgW, imgH = map(int, args.res.split("x"))
# Create a folder, if it doesn't exist
cwd = getcwd()
dirpath = path.join(cwd,dirname)
if not path.exists(dirpath):
makedirs(dirpath)
# Prevent taken frame overwriting
imgnum = 1
key_flag = False
while 1:
filename = f"{dirname}_{imgnum}.png"
if not path.exists(path.join(dirpath, filename)):
break
imgnum +=1
#### Initialize camera #####
# Load the tuning for the RPi IR-Cut camera.
# Renamed the original file (ov5647.json) to custom.
tuning_file = Picamera2.load_tuning_file("ov5647_custom.json")
# Call picamera2 constructor and pass loaded tuning file.
picam2 = Picamera2(tuning=tuning_file)
# Set options for saving images
picam2.options["quality"] = 95 # best quality
picam2.options["compress_level"] = 0 # no compression
# Print the hints for the user
print("\n##############################")
print("### Image taker calibrated ###")
print("##############################")
print("For help run the script with the '--help' option.")
print("\nPress 'p' to take an image, they will be saved in the '{}' folder.".format(dirname))
print("To quit the application press 'q'.\n")
# Create preview configuration with denoising
picam2.configure(picam2.create_preview_configuration(main={"format": "XRGB8888", "size": (1920, 1080)}, controls={"NoiseReductionMode":controls.draft.NoiseReductionModeEnum.HighQuality}))
picam2.start()
# Setup the preview Window with OpenCV (PiCamera2 not compatible)
# Set size, position and window size
winname = "Calibrated (undistorted) Image taker"
namedWindow(winname, WINDOW_NORMAL)
resizeWindow(winname, 1000, 900)
moveWindow(winname, 915, 72)
startWindowThread()
# Load the calibration file with params
with open("calibrate_camera.json", "r") as f:
calibration_file = load(f)
mtx = array(calibration_file["mtx"], dtype=float64)
dist = array(calibration_file["dist"], dtype=float64)
try:
while 1:
# request - faster?
#request = picam2.capture_request()
#array = request.make_array("main")
#2 direct capture -faster ?
array = picam2.capture_array("main")
new_cv_img = cvtColor(array, COLOR_RGBA2RGB)
h, w = new_cv_img.shape[:2]
optimal_camera_matrix, roi = getOptimalNewCameraMatrix(mtx, dist, (w, h), 0, (w, h))
dst = undistort(new_cv_img, mtx, dist, None, optimal_camera_matrix)
# hold the default image size (not cropping)
#x, y, w, h = roi
#dst = dst[y:y+h, x:x+w]
imshow(winname, dst)
if is_pressed("p"):
if key_flag is False:
key_flag = True
filename = "".join([dirname, "_", str(imgnum), ".png"])
savepath = path.join(dirpath, filename)
imwrite(savepath, dst)
print("\rOpenCV image saved from request -> {}".format(filename))
imgnum+=1
else:
key_flag = False
#request.release()
elif is_pressed("q"):
print("\r++++++++++++++++++++++++++++++++++++++++++++++")
print("\rInterruption: stop preview and close camera...")
break
finally:
destroyAllWindows()
picam2.stop()
picam2.close()
tcflush(stdin, TCIOFLUSH)