Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hackerb9/passportpix

Take a passport photo of proper dimensions using computer vision
https://github.com/hackerb9/passportpix

camera face-detection image-processing opencv-python passport photo

Last synced: 3 months ago
JSON representation

Take a passport photo of proper dimensions using computer vision

Awesome Lists containing this project

README

        

# passportpix

Take a passport photo of precisely the proper dimensions using
computer vision to pan and zoom on the face.

Defaults to US Passport requirements, but can be modified for others.

Shows live camera view. Automatically centers and zooms image to be
precisely correct for passport photos. Hit spacebar to snap the photo
to "passport.jpg" and q to quit.

## How to run

``` bash
apt install python-opencv opencv-data
git clone https://github.com/hackerb9/passportpix
cd passportpix
./passport.py
```

## Notes

### Resolution

The image saved to a file is higher resolution than the preview shown
on screen. The face detection routine is a bit CPU hungry so the image
is downscaled to fit in a 640x640 square before processing to get a
better frame rate. Likewise, some low-end computers, such as the
Raspberry Pi, struggle with displaying large images rapidly, so the
downscaled image is used for screen display.

### TIP

If you leave an image viewer, such as `eog passport.jpg`, running
in the background, you'll see the picture update immediately so you
can tell if you like it or not.

### TIP

If you need a "portrait" photo (taller than it is wide), you can
improve the image resolution by rotating your camera sideways and edit
the `camera_rotation` variable at the top of the file. (Or hit the 'r'
key).

## Customization

The default setup is correct for US Passport photos:

| Variable | Description | Setting for US Passport |
|--------------|--------------------------------------------------------------------------|---------------------------------|
| photo_aspect | Ratio of width to height | 1
(square) |
| eye_distance | Distance between eyes, expressed as a fraction of the picture width | 2/12
(= ⅓" on a 2" width) |
| eye_height | Distance of eyes from bottom of picture, as a fraction of picture height | 7/12
(= 1⅙" on a 2" height) |

These variables are listed at the top of passport.py and can be
changed there.

Click to see an example customization

### Example customization

If one need a visa to visit China, the photo requirements as of 2020 are:

| Variable | Description | Setting for CN Visa |
|--------------|--------------------------------------------------------------------------|---------------------------------|
| photo_width | Width of printed photo | 33 |
| photo_height | Height of printed photo | 48 |
| photo_units | Unit of measurement of width and height | mm |
| photo_aspect | Ratio of width to height | 33/48 |
| eye_height | Distance of eyes from bottom of picture, as a fraction of picture height | 24/48
(precisely in middle) |
| chin_height | Distance of chin from bottom of picture, as a fraction of picture height | 7/48 |

So, one would set:

``` python
# Setting for Chinese Visa photo
photo_width = 33.0
photo_height = 48.0
photo_units = "mm"
photo_aspect = photo_width/photo_height
eye_height = 24.0 / 48.0
chin_height = 7.0 / 48.0
use_chin_height = True
```

Note that by default `use_chin_height` is False, which causes
`eye_distance` to be used for calculating the scaling instead of
`chin_height`. You can also hit the Tab key to switch
between those two methods.

## Current keys

* Space: Save snapshot to passport.jpg
* q or Esc: Quit
* f: Toggle fullscreen

Less useful keys:
* m: Toggle mirroring
* r: Increment camera rotation by 90°
* Tab: Toggle between US (eye distance) and Chinese (chin
distance) photo requirements. Does not change photo dimensions.
* Enter: Show debugging info, save debugging images

### Experimental keys for resolution
Click to see more keys

These keys change the downscale resolution which is used for both the
computer vision processing and for display on the screen. They do not
affect the output resolution in the saved file.

| Key | Maximum height or width |
|--------------|-------------------------|
| 1 | 160 |
| 2 | 320 |
| 3 | 640 (default) |
| 4 | 960 |
| 5 | 1280 |
| 0 | Native resolution |

Note that OpenCV's builtin face detection algorithms failed for me on
160×160 images.

## Current Assumptions

* I assume you always want the highest resolution possible from your camera.

* You'll need to have 'python-opencv' installed. (`apt install python-opencv`)

## Bugs and Future Features.

* Cropped image jitters as eye locations are approximated. Ought to
show uncropped camera view either in a second window or alone with a
rectangle showing how the image will be cropped.

* OpenCV cannot write the proper DPI to the JPEG file, so it will not
print out at the correct size without massaging. This is annoying, but
is easy enough to work around that I'm not fixing it before the
release.

* You can only take one photo. Every photo you take overwrites the
previous 'passport.jpg' file.

* Only the first camera is opened. You can change that by editing
`camera_device` at the beginning of the file.

* When recentering the face, especially if it is very close to the
camera, there may not be enough picture from the camera to extend all
the way to the edge of the final photo. The program should warn about
this and give a visual indication of which way to move to fix it.

* If your face is too far away, the camera will zoom in too much,
causing a blurry picture. This program ought to detect if height or
width is less than 600 and ask the user to step closer.

## Debugging & such
Click to see info about debugging

Mostly reminders to myself.

* To list all resolutions a camera is capable of:

```
v4l2-ctl --list-formats-ext
```

* OpenCV appears to prefer uncompressed video, even if a camera can
provide a higher resolution & frame rate with compression turned on.

This may not be a problem. I've added functionality to allow for
compression and lower FPS, but even though the nominal resolution
was higher, the quality was noticeably worse than simply scaling the
uncompressed video. (At least on the cameras I tried). If you want
to give it a shot, change the variables `camera_codec='MJPG'` or
`camera_fps=15`.

* To print out the current GUI properties and other debugging info,
hit Enter.

* OpenCV has unnecessarily confusing GUI window properties. In
particular, it appears OpenCV was originally written using simple
integer Booleans (0 or 1), but someone later came along and decided
that was too sloppy and renamed them all. However, instead of using
the typical True or False, they came up with new names for truth
values for each variable so each has its own nearly-unique way of
being used.

I found this silly and hard to read, so I do not follow that
practice. For example, I have replaced the following code:

```python
isFull = (cv2.getWindowProperty(title, cv2.WND_PROP_FULLSCREEN) == cv2.WINDOW_FULLSCREEN)a
cv2.setWindowProperty(title,
cv2.WND_PROP_FULLSCREEN,
cv2.WINDOW_NORMAL if isFull else cv2.WINDOW_FULLSCREEN)
```

with:

```python
isFull = cv2.getWindowProperty(title, cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty(title, cv2.WND_PROP_FULLSCREEN, 1 - isFull)
```

* Here are the OpenCV window properties and their official
documentation (as of 2023). _(Italics mine.)_

* `WND_PROP_FULLSCREEN`

fullscreen property (can be `WINDOW_NORMAL` or `WINDOW_FULLSCREEN`).

_Boolean `NORMAL` is 0 and `FULLSCREEN` is 1_

* `WND_PROP_AUTOSIZE`

autosize property (can be `WINDOW_NORMAL`, 0, or `WINDOW_AUTOSIZE`, 1).

_Boolean `NORMAL` is 0 and `AUTOSIZE` is 1_

* `WND_PROP_ASPECT_RATIO`

window's aspect ration (can be `WINDOW_FREERATIO` or `WINDOW_KEEPRATIO`).

_Boolean `KEEPRATIO` is 0 and `FREERATIO` is 256_

* `WND_PROP_OPENGL`

opengl support.

_Presumed to be Boolean, but documentation does not specify._

* `WND_PROP_VISIBLE`

checks whether the window exists and is visible.

_Presumed to be Boolean, but documentation does not specify._

* `WND_PROP_TOPMOST`

property to toggle normal window being topmost or not.

_Presumed to be Boolean, but documentation does not specify._

## Bonus: Harpy.py

Here is a simple Python script for face detection in live video using
OpenCV. harpy.py. Short and easy to modify if
you want to start another project like this.