Skip to content

Commit 69072ab

Browse files
IanTBlackdavidplowman
authored andcommitted
Large code reorganisation, addition of tests (see below)
Files are moved into a number of new subdirectories. A Picamera2.start_preview function has been added in place of direct preview object creation. A "tests" folder added with some initial tests. All the examples are updated. Scripts added for style checking and running tests.
1 parent 6251ae8 commit 69072ab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1722
-509
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
__pycache__
22
*~
3+
/.spyproject
4+
.spyproject
5+
/.idea
6+
.idea

README.md

+40-13
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ For the time being, the documentation here is mostly based on a number of suppli
1010

1111
## Installation
1212

13-
These instructions are for a fresh 32-bit Bullseye image running on a Pi 4B. On other platforms your mileage may vary - good luck. Note that I found OpenCV more of a pain to install on a 64-bit image, but you may know better incantations than I do (please share!).
13+
These instructions are for a fresh 32-bit Bullseye image running on a Pi 4B. On other platforms your mileage may vary - good luck.
1414

1515
First install and build *libcamera* according to the [standard instructions](https://www.raspberrypi.com/documentation/accessories/camera.html#building-libcamera) but with the following *two* differences:
1616

@@ -55,16 +55,35 @@ To make everything run, you will also have to set your `PYTHONPATH` environment
5555
export PYTHONPATH=/home/pi/picamera2:/home/pi/libcamera/build/src/py:/home/pi/kmsxx/build/py:/home/pi/python-v4l2
5656
```
5757

58-
**A note on OpenCV**
58+
**OpenCV**
5959

60-
I had some difficulties installing the latest version, and the version from apt didn't seem to include the Haar classifiers. But the following appears to work:
60+
OpenCV can be installed from `apt` as follows. Normally this should avoid the very long build times that can sometimes be required by other methods.
6161

6262
```
63-
sudo pip3 install opencv-python==4.4.0.46
64-
sudo apt install -y libatlas-base-dev
65-
sudo pip3 install numpy --upgrade
63+
sudo apt install -y python3-opencv
64+
sudo apt install -y opencv-data
6665
```
6766

67+
## Contributing
68+
69+
We are happy to receive pull requests that will fix bugs, add features and generally improve the code. If possible, pull requests would ideally be:
70+
71+
- Restricted to one change or feature each.
72+
- The commit history should consist of a number of commits that are as easy to review as possible.
73+
- Where changes are likely to be more involved, we would invite authors to start a discussion with us first so that we can agree a good way forward.
74+
- All the tests and examples should be working after each commit in the pull request. We'll shortly be adding some automated testing to the repository to make it easier to test if things have become broken.
75+
- Any documentation should be updated accordingly. Where appropriate, new examples and tests would be welcomed.
76+
- The author of the pull request needs to agree that they are donating the work to this project and to Raspberry Pi Ltd., so that we can continue to distribute it as open source to all our users. To indicate your agreement to this, we would ask that you finish commit messages with a blank line followed by `Signed-off-by: Your Name <your.email@your.domain>`.
77+
- We'd like to conform to the common Python _PEP 8_ coding style wherever possible. To facilitate this we would recommend putting
78+
```
79+
#!/bin/bash
80+
81+
exec git diff --cached | ./tools/checkstyle.py --staged
82+
```
83+
into your `.git/hooks/pre-commit` file.
84+
85+
Thank you!
86+
6887
## How *Picamera2* Works
6988

7089
Readers are recommended to refer to the supplied [examples](#examples) in conjunction with the descriptions below.
@@ -74,7 +93,7 @@ Readers are recommended to refer to the supplied [examples](#examples) in conjun
7493
The camera system should be opened as shown.
7594

7695
```
77-
from picamera2 import *
96+
from picamera2.picamera2 import *
7897
7998
picam2 = Picamera2()
8099
```
@@ -157,26 +176,34 @@ The *Picamera2* class implements most of the camera functionality, however, it d
157176
- Use the `NullPreview` class. This class actually generates no preview window at all and merely supplies an event loop that drives the camera.
158177
- In a Qt application, the `QPicamer2` or `QGlPicamera2` widgets are provided and automatically use the Qt event loop to drive the camera.
159178

160-
In all cases creating one of these objects starts the event loop, though it will not receive any frames until `Picamera2.start` is called.
179+
To start the event loop, the `start_preview` method should be called. It can be passed an actual preview object, or for convenience can be passed one of the Preview enum values (see below). If given no arguments at all, a `NullPreview` is created. When running under a Qt even loop, `start_preview` should _not_ be called at all.
161180

162181
Example:
163182

164183
```
165-
from picamera2 import *
166-
from qt_gl_preview import *
184+
from picamera2.picamera2 import *
167185
168186
picam2 = Picamera2()
169-
preview = QtGlPreview(picam2)
187+
picam2.start_preview(Preview.QTGL)
170188
171189
config = picam2.preview_configuration()
172190
picam2.configure(config)
173191
174192
picam2.start()
175193
```
176194

177-
To use the DRM preview window, use `from drm_preview import *` and `preview = DrmPreview(picam2)` instead.
195+
Note that
196+
```
197+
from picamera2.previews.qt_gl_preview import *
198+
picam2.start_preview(QtGlPreview())
199+
```
200+
is equivalent to `picam2.start_preview(Preview.QTGL)`.
201+
202+
To use the DRM preview window, use `picam2.start_preview(Preview.DRM)` instead.
203+
204+
To use the Qt (non-GL) preview window, use `picam2.start_preview(Preview.QT)` instead.
178205

179-
For no preview window at all, use `from null_preview import *` and `preview = NullPreview(picam2)` instead.
206+
For no preview window at all, use `picam2.start_preview()` or `picam2.start_preview(Preview.NULL)`.
180207

181208
Please refer to the supplied examples for more information.
182209

examples/app_capture.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,29 @@
33
from PyQt5 import QtCore, QtGui, QtWidgets
44
from PyQt5.QtWidgets import *
55

6-
from q_gl_picamera2 import *
7-
from picamera2 import *
6+
from picamera2.previews.q_gl_picamera2 import *
7+
from picamera2.picamera2 import *
8+
89

910
def request_callback(request):
10-
label.setText(''.join("{}: {}\n".format(k, v) for k, v in request.get_metadata().items()))
11+
label.setText(''.join("{}: {}\n".format(k, v) for k, v in request.get_metadata().items()))
12+
1113

1214
picam2 = Picamera2()
1315
picam2.request_callback = request_callback
1416
picam2.configure(picam2.preview_configuration(main={"size": (800, 600)}))
1517

1618
app = QApplication([])
1719

20+
1821
def on_button_clicked():
1922
if not picam2.async_operation_in_progress:
2023
cfg = picam2.still_configuration()
2124
picam2.switch_mode_and_capture_file(cfg, "test.jpg", wait=False, signal_function=None)
2225
else:
2326
print("Busy!")
2427

28+
2529
qpicamera2 = QGlPicamera2(picam2, width=800, height=600)
2630
button = QPushButton("Click to capture JPEG")
2731
button.clicked.connect(on_button_clicked)

examples/capture_full_res.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
# Capture a JPEG while still running in the preview mode.
44

5-
from qt_gl_preview import *
6-
from picamera2 import *
5+
from picamera2.picamera2 import *
76
import time
87

98
picam2 = Picamera2()
10-
preview = QtGlPreview(picam2)
9+
picam2.start_preview(Preview.QTGL)
1110

1211
preview_config = picam2.preview_configuration()
1312
capture_config = picam2.still_configuration()

examples/capture_headless.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#!//usr/bin/python3
22

3-
from picamera2 import *
4-
from null_preview import *
3+
from picamera2.picamera2 import *
54

65
picam2 = Picamera2()
76
config = picam2.still_configuration()
87
picam2.configure(config)
98

10-
preview = NullPreview(picam2)
9+
picam2.start_preview()
1110

1211
picam2.start()
1312

examples/capture_image_full_res.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
# Capture a full resolution image to memory rather than to a file.
44

5-
from qt_gl_preview import *
6-
from picamera2 import *
5+
from picamera2.picamera2 import *
76
import time
87

98
picam2 = Picamera2()
10-
preview = QtGlPreview(picam2)
11-
9+
picam2.start_preview(Preview.QTGL)
1210
preview_config = picam2.preview_configuration()
1311
capture_config = picam2.still_configuration()
14-
picam2.configure(preview_config)
1512

13+
picam2.configure(preview_config)
1614
picam2.start()
1715
time.sleep(2)
1816

1917
image = picam2.switch_mode_and_capture_image(capture_config)
2018
image.show()
19+
20+
21+
time.sleep(5)
22+
23+
picam2.close()

examples/capture_jpeg.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
# Capture a JPEG while still running in the preview mode. When you
44
# capture to a file, the return value is the metadata for that image.
55

6-
from qt_gl_preview import *
7-
from picamera2 import *
6+
from picamera2.picamera2 import *
87
import time
98

109
picam2 = Picamera2()
11-
preview = QtGlPreview(picam2)
1210

1311
preview_config = picam2.preview_configuration(main={"size": (800, 600)})
1412
picam2.configure(preview_config)
1513

14+
picam2.start_preview(Preview.QTGL)
15+
1616
picam2.start()
1717
time.sleep(2)
1818

1919
metadata = picam2.capture_file("test.jpg")
2020
print(metadata)
21+
22+
picam2.close()

examples/capture_mjpeg.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
#!/usr/bin/python3
22

3-
from null_preview import *
4-
from jpeg_encoder import *
5-
from picamera2 import *
3+
from picamera2.encoders.jpeg_encoder import *
4+
from picamera2.picamera2 import *
65
import time
76

87
picam2 = Picamera2()
98
video_config = picam2.video_configuration(main={"size": (1920, 1080)})
109
picam2.configure(video_config)
1110

12-
preview = NullPreview(picam2)
11+
picam2.start_preview()
1312
encoder = JpegEncoder(q=70)
1413

1514
picam2.start_recording(encoder, 'test.mjpeg')

examples/capture_motion.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#!/usr/bin/python3
22

3-
from null_preview import *
4-
from h264_encoder import *
5-
from picamera2 import *
3+
from picamera2.encoders.h264_encoder import *
4+
from picamera2.picamera2 import *
65
from signal import pause
76
import numpy as np
87
import time
@@ -12,7 +11,7 @@
1211
video_config = picam2.video_configuration(main={"size": (1280, 720), "format": "RGB888"},
1312
lores={"size": lsize, "format": "YUV420"})
1413
picam2.configure(video_config)
15-
preview = NullPreview(picam2)
14+
picam2.start_preview()
1615
encoder = H264Encoder(1000000)
1716
picam2.encoder = encoder
1817
picam2.start()

examples/capture_png.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
# Capture a PNG while still running in the preview mode.
44

5-
from qt_gl_preview import *
6-
from picamera2 import *
5+
from picamera2.picamera2 import *
76
import time
87

98
picam2 = Picamera2()
10-
preview = QtGlPreview(picam2)
9+
picam2.start_preview(Preview.QTGL)
1110

1211
preview_config = picam2.preview_configuration(main={"size": (800, 600)})
1312
picam2.configure(preview_config)

examples/capture_stream.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
#!/usr/bin/python3
22

3-
from null_preview import *
4-
from h264_encoder import *
5-
from picamera2 import *
3+
from picamera2.encoders.h264_encoder import *
4+
from picamera2.picamera2 import *
65
import socket
76
import time
87
import os
98

109
picam2 = Picamera2()
1110
video_config = picam2.video_configuration({"size": (1280, 720)})
1211
picam2.configure(video_config)
13-
preview = NullPreview(picam2)
12+
picam2.start_preview()
1413
encoder = H264Encoder(1000000)
1514

1615
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:

examples/capture_video.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
#!/usr/bin/python3
22

3-
from null_preview import *
4-
from h264_encoder import *
5-
from picamera2 import *
3+
from picamera2.encoders.h264_encoder import *
4+
from picamera2.picamera2 import *
65
import time
76
import os
87

98
picam2 = Picamera2()
109
video_config = picam2.video_configuration()
1110
picam2.configure(video_config)
1211

13-
preview = NullPreview(picam2)
12+
picam2.start_preview()
1413
encoder = H264Encoder(10000000)
1514

1615
picam2.start_recording(encoder, 'test.h264')

examples/controls.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
# Example of setting controls. Here, after one second, we fix the AGC/AEC
44
# to the values it has reached whereafter it will no longer change.
55

6-
from qt_gl_preview import *
7-
from picamera2 import *
6+
from picamera2.picamera2 import *
87
import time
98

109
picam2 = Picamera2()
11-
preview = QtGlPreview(picam2)
10+
picam2.start_preview(Preview.QTGL)
1211

1312
preview_config = picam2.preview_configuration()
1413
picam2.configure(preview_config)
@@ -17,7 +16,7 @@
1716
time.sleep(1)
1817

1918
metadata = picam2.capture_metadata()
20-
controls = {c : metadata[c] for c in ["ExposureTime", "AnalogueGain", "ColourGains"]}
19+
controls = {c: metadata[c] for c in ["ExposureTime", "AnalogueGain", "ColourGains"]}
2120
print(controls)
2221

2322
picam2.set_controls(controls)

examples/controls_2.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
# Another (simpler!) way to fix the AEC/AGC and AWB.
44

5-
from qt_gl_preview import *
6-
from picamera2 import *
5+
from picamera2.picamera2 import *
76
import time
87

98
picam2 = Picamera2()
10-
preview = QtGlPreview(picam2)
9+
picam2.start_preview(Preview.QTGL)
1110

1211
preview_config = picam2.preview_configuration()
1312
picam2.configure(preview_config)

examples/exposure_fixed.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
# Start camera with fixed exposure and gain.
44

5-
from qt_gl_preview import *
6-
from picamera2 import *
5+
from picamera2.picamera2 import *
76
import time
87

98
picam2 = Picamera2()
10-
preview = QtGlPreview(picam2)
9+
picam2.start_preview(Preview.QTGL)
1110

1211
preview_config = picam2.preview_configuration()
1312
picam2.configure(preview_config)

examples/metadata.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
# Obtain the current camera control values in the image metadata.
44

5-
from qt_gl_preview import *
6-
from picamera2 import *
5+
from picamera2.picamera2 import *
76
import time
87

98
picam2 = Picamera2()
10-
preview = QtGlPreview(picam2)
9+
picam2.start_preview(Preview.QTGL)
1110

1211
preview_config = picam2.preview_configuration()
1312
picam2.configure(preview_config)

0 commit comments

Comments
 (0)