Skip to content

Commit 21966ae

Browse files
committed
Camera section finished
1 parent 784ffc0 commit 21966ae

File tree

6 files changed

+249
-9
lines changed

6 files changed

+249
-9
lines changed
5.28 MB
Loading
7.01 MB
Loading
9.73 MB
Loading
4.52 MB
Loading
6.77 MB
Loading

content/hardware/04.pro/shields/portenta-vision-shield/tutorials/user-manual/content.md

Lines changed: 249 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,34 +195,34 @@ From the above example script, we can highlight the main functions:
195195

196196
- `sensor.snapshot()` lets you take a picture and return the image so you can save it, stream it or process it.
197197

198-
### Camera
198+
## Camera
199199

200200
The Portenta Vision Shields's main feature is its onboard camera, based on the HM01B0 ultralow power CMOS image sensor. It is perfect for Machine Learning applications such as object detection, image classification, machine/computer vision, robotics, IoT, and more.
201201

202202
![Onboard camera sensor](assets/camera.png)
203203

204-
#### Main Camera Features
204+
**Main Camera Features**
205205

206206
- Ultra-Low-Power Image Sensor designed for always-on vision devices and applications
207207
- High-sensitivity 3.6 μ BrightSenseTM pixel technology Window, vertical flip and horizontal mirror readout
208208
- Programmable black level calibration target, frame size, frame rate, exposure, analog gain (up to 8x) and digital gain (up to 4x)
209209
- Automatic exposure and gain control loop with support for 50 Hz / 60 Hz flicker avoidance
210210
- Motion Detection circuit with programmable ROI and detection threshold with digital output to serve as an interrupt
211211

212-
#### Supported Resolutions
212+
**Supported Resolutions**
213213

214214
- QQVGA (160x120) at 15, 30, 60 and 120 FPS
215215
- QVGA (320x240) at 15, 30 and 60 FPS
216216
- B320X320 (320x320) at 15, 30 and 45 FPS
217217

218-
#### Power Consumption
218+
**Power Consumption**
219219
- < 1.1 mW QQVGA resolution at 30 FPS,
220220
- < 2 mW QVGA resolution at 30 FPS
221221
- < 4 mW QVGA resolution at 60 FPS
222222

223223
The Vision Shield is primarily intended to be used with the OpenMV MicroPython ecosystem. So, it's recommended to use this IDE for machine vision applications.
224224

225-
#### Snapshot Example
225+
### Snapshot Example
226226

227227
The example code below lets you take a picture and save it on the Portenta H7 local storage or in a Micro SD card as `example.jpg`.
228228

@@ -257,7 +257,7 @@ After the snapshot is taken, reset the board by pressing the reset button and th
257257

258258
![Snapshot saved in H7 local storage](assets/snapshot.png)
259259

260-
#### Video Recording Example
260+
### Video Recording Example
261261

262262
The example code below lets you record a video and save it on the Portenta H7 local storage or in a Micro SD card as `example.mjpeg`.
263263

@@ -291,13 +291,253 @@ raise (Exception("Please reset the camera to see the new file."))
291291

292292
![Video saved in local storage](assets/video-ani.gif)
293293

294-
#### Sensor Control
294+
### Sensor Control
295295

296-
#### Bar Codes
296+
There are several functions that allow us to configure the behavior of the camera sensor and adapt it to our needs.
297+
298+
**Gain**: the gain is related to the sensor sensitivity and affects how bright or dark the final image will be.
299+
300+
With the following functions, you can control the camera gain:
301+
302+
```python
303+
sensor.set_auto_gain(True, gain_db_ceiling=16.0) # True = auto gain enabled, with a max limited to gain_db_ceiling parameter.
304+
sensor.set_auto_gain(False, gain_db=8.0) # False = auto gain disabled, fixed to gain_db parameter.
305+
```
306+
![Auto Gain example](assets/gain.gif)
307+
308+
**Orientation**: flip the image captured to meet your application's needs.
309+
310+
With the following functions, you can control the image orientation:
311+
312+
```python
313+
sensor.set_hmirror(True) # Enable horizontal mirror | undo the mirror if False
314+
sensor.set_vflip(True) # Enable the vertical flip | undo the flip if False
315+
```
316+
317+
You can find complete `Sensor Control` examples in **File > Examples > Camera > Sensor Control** of the OpenMV IDE.
318+
319+
### Bar and QR Codes
320+
321+
The Vision Shield is ideal for production line inspections, in these examples, we are going to be locating and reading bar codes and QR codes.
322+
323+
#### Bar Codes
324+
325+
This example code can be found in **File > Examples > Barcodes** in the OpenMV IDE.
326+
327+
```python
328+
import sensor
329+
import image
330+
import time
331+
import math
332+
333+
sensor.reset()
334+
sensor.set_pixformat(sensor.GRAYSCALE)
335+
sensor.set_framesize(sensor.QVGA) # High Res!
336+
sensor.set_windowing((640, 80)) # V Res of 80 == less work (40 for 2X the speed).
337+
sensor.skip_frames(time=2000)
338+
sensor.set_auto_gain(False) # must turn this off to prevent image washout...
339+
sensor.set_auto_whitebal(False) # must turn this off to prevent image washout...
340+
clock = time.clock()
341+
342+
# Barcode detection can run at the full 640x480 resolution of your OpenMV Cam's.
343+
344+
def barcode_name(code):
345+
if code.type() == image.EAN2:
346+
return "EAN2"
347+
if code.type() == image.EAN5:
348+
return "EAN5"
349+
if code.type() == image.EAN8:
350+
return "EAN8"
351+
if code.type() == image.UPCE:
352+
return "UPCE"
353+
if code.type() == image.ISBN10:
354+
return "ISBN10"
355+
if code.type() == image.UPCA:
356+
return "UPCA"
357+
if code.type() == image.EAN13:
358+
return "EAN13"
359+
if code.type() == image.ISBN13:
360+
return "ISBN13"
361+
if code.type() == image.I25:
362+
return "I25"
363+
if code.type() == image.DATABAR:
364+
return "DATABAR"
365+
if code.type() == image.DATABAR_EXP:
366+
return "DATABAR_EXP"
367+
if code.type() == image.CODABAR:
368+
return "CODABAR"
369+
if code.type() == image.CODE39:
370+
return "CODE39"
371+
if code.type() == image.PDF417:
372+
return "PDF417"
373+
if code.type() == image.CODE93:
374+
return "CODE93"
375+
if code.type() == image.CODE128:
376+
return "CODE128"
377+
378+
379+
while True:
380+
clock.tick()
381+
img = sensor.snapshot()
382+
codes = img.find_barcodes()
383+
for code in codes:
384+
img.draw_rectangle(code.rect())
385+
print_args = (
386+
barcode_name(code),
387+
code.payload(),
388+
(180 * code.rotation()) / math.pi,
389+
code.quality(),
390+
clock.fps(),
391+
)
392+
print(
393+
'Barcode %s, Payload "%s", rotation %f (degrees), quality %d, FPS %f'
394+
% print_args
395+
)
396+
if not codes:
397+
print("FPS %f" % clock.fps())
398+
```
399+
400+
The format, payload, orientation and quality will be printed out in the Serial Monitor when a bar code becomes readable.
401+
402+
![Bar codes reading](assets/bar-codes.gif)
297403

298404
#### QR Codes
299405

300-
#### Face Tracking
406+
This example code can be found in **File > Examples > Barcodes** in the OpenMV IDE.
407+
408+
```python
409+
import sensor
410+
import time
411+
412+
sensor.reset()
413+
sensor.set_pixformat(sensor.GRAYSCALE)
414+
sensor.set_framesize(sensor.B320X320)
415+
sensor.skip_frames(time=2000)
416+
sensor.set_auto_gain(False) # must turn this off to prevent image washout...
417+
clock = time.clock()
418+
419+
while True:
420+
clock.tick()
421+
img = sensor.snapshot()
422+
img.lens_corr(1.8) # strength of 1.8 is good for the 2.8mm lens.
423+
for code in img.find_qrcodes():
424+
img.draw_rectangle(code.rect(), color=(255, 255, 0))
425+
print(code)
426+
print(clock.fps())
427+
```
428+
The coordinates, size, and payload will be printed out in the Serial Monitor when a QR code becomes readable.
429+
430+
![QR codes reading](assets/qr.gif)
431+
432+
### Face Tracking
433+
434+
You can track faces using the built-in FOMO face detection model. This example can be found in **File > Examples > Machine Learning > TensorFlow > tf_object_detection.py**.
435+
436+
This script will draw a circle on each detected face and will print their coordinates in the Serial Monitor.
437+
438+
```python
439+
import sensor
440+
import time
441+
import tf
442+
import math
443+
444+
sensor.reset() # Reset and initialize the sensor.
445+
sensor.set_pixformat(sensor.GRAYSCALE) # Set pixel format to RGB565 (or GRAYSCALE)
446+
sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)
447+
sensor.set_windowing((240, 240)) # Set 240x240 window.
448+
sensor.skip_frames(time=2000) # Let the camera adjust.
449+
450+
min_confidence = 0.4
451+
452+
# Load built-in FOMO face detection model
453+
labels, net = tf.load_builtin_model("fomo_face_detection")
454+
455+
# Alternatively, models can be loaded from the filesystem storage.
456+
# net = tf.load('<object_detection_network>', load_to_fb=True)
457+
# labels = [line.rstrip('\n') for line in open("labels.txt")]
458+
459+
colors = [ # Add more colors if you are detecting more than 7 types of classes at once.
460+
(255, 0, 0),
461+
(0, 255, 0),
462+
(255, 255, 0),
463+
(0, 0, 255),
464+
(255, 0, 255),
465+
(0, 255, 255),
466+
(255, 255, 255),
467+
]
468+
469+
clock = time.clock()
470+
while True:
471+
clock.tick()
472+
473+
img = sensor.snapshot()
474+
475+
# detect() returns all objects found in the image (splitted out per class already)
476+
# we skip class index 0, as that is the background, and then draw circles of the center
477+
# of our objects
478+
479+
for i, detection_list in enumerate(
480+
net.detect(img, thresholds=[(math.ceil(min_confidence * 255), 255)])
481+
):
482+
if i == 0:
483+
continue # background class
484+
if len(detection_list) == 0:
485+
continue # no detections for this class?
486+
487+
print("********** %s **********" % labels[i])
488+
for d in detection_list:
489+
[x, y, w, h] = d.rect()
490+
center_x = math.floor(x + (w / 2))
491+
center_y = math.floor(y + (h / 2))
492+
print(f"x {center_x}\ty {center_y}")
493+
img.draw_circle((center_x, center_y, 12), color=colors[i], thickness=2)
494+
495+
print(clock.fps(), "fps", end="\n")
496+
```
497+
498+
You can load different Machine Learning models for detecting other objects, for example, persons.
499+
500+
Download the `.tflite` and `.txt` files from this [repository](https://github.com/openmv/tensorflow-lib/tree/master/libtf/models) and copy them to the Portenta H7 local storage.
501+
502+
Use the following example script to run the **person detection** model.
503+
504+
```python
505+
import sensor
506+
import time
507+
import tf
508+
import math
509+
import uos, gc
510+
511+
sensor.reset() # Reset and initialize the sensor.
512+
sensor.set_pixformat(sensor.GRAYSCALE) # Set pixel format to RGB565 (or GRAYSCALE)
513+
sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)
514+
sensor.set_windowing((240, 240)) # Set 240x240 window.
515+
sensor.skip_frames(time=2000) # Let the camera adjust.
516+
517+
net = tf.load('person_detection.tflite', load_to_fb=True)
518+
labels = [line.rstrip('\n') for line in open("person_detection.txt")]
519+
520+
521+
clock = time.clock()
522+
while True:
523+
clock.tick()
524+
525+
img = sensor.snapshot()
526+
527+
for obj in net.classify(img, min_scale = 1.0, scale_mul= 0.8, x_overlap = 0.5, y_overlap = 0.5):
528+
print("*********** \nDetections at [x=%d,y=%d, w=%d, h=%d]" % obj.rect())
529+
img.draw_rectangle(obj.rect())
530+
predictions_list = list(zip(labels,obj.output()))
531+
532+
for i in range(len(predictions_list)):
533+
print ("%s = %f" % (predictions_list[i][0], predictions_list[i][1]))
534+
535+
print(clock.fps(), "fps", end="\n")
536+
```
537+
538+
When a person is in the field of view of the camera, you should see the inference result for `person` rising above 70% of certainty.
539+
540+
![Person detection example running](assets/person-detect.gif)
301541

302542
### Microphone
303543

0 commit comments

Comments
 (0)