Skip to content

Commit

Permalink
fix(cli): fix wrong spelling, do not swap transformer, fix command in…
Browse files Browse the repository at this point in the history
… README.md (#37)

* fix(cli): fix border spelling

* fix(cli): do not swap transformer

* docs(readme): update README.md

* docs(readme): update README.md

* docs(readme): set text color using latex

* fix(readme): use inline latex

* docs(readme): add math for calibration

* docs(readme): fix math

* docs(readme): update math
  • Loading branch information
34j authored May 11, 2024
1 parent 38d845c commit 2aa7951
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 27 deletions.
72 changes: 54 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ v1c lr left.jpg right.jpg

If left and right image paths are the same, the image is divided into two halves (left and right, SBS) and processed as if they were separate images.

## Advanced usage

### Automatic image search

If one of left or right image path is a directory, the program will search for the closest image (in terms of creation time) in the other directory.
Expand All @@ -78,19 +80,6 @@ v1c lr left.jpg right_dir -ac 1 # the clock of the right camera is 1 second fast
v1c lr left_dir right.jpg -ac 1 # the clock of the right camera is 1 second faster / ahead
```

### Custom conversion model

You can also specify the conversion model by adding Python code directly to the `--transformer` option:

```shell
v1c lr left.jpg right.jpg ---transformer "EquirectangularEncoder() * Euclidean3DRotator(from_rotation_vector([0, np.pi / 4, 0])) * FisheyeDecoder("equidistant")"
```

If tuple, the first transformer is applied to the left image and the second transformer is applied to the right image. If a single transformer is given, it is applied to both images.

Please refer to the [API documentation](https://vr180-convert.readthedocs.io/) for the available transformers and their parameters.
For `from_rotation_vector`, please refer to the [numpy-quaternion documentation](https://quaternion.readthedocs.io/en/latest/Package%20API%3A/quaternion/#from_rotation_vector).

### Radius estimation

The radius of the non-black area of the input image is assumed by counting black pixels by default, but it would be better to specify it manually to get stable results:
Expand All @@ -102,7 +91,7 @@ v1c lr left.jpg right.jpg --radius max # min(width, height) / 2

### Calibration

Rotation matching using the least-squares method can be performed by clicking corresponding points that can be regarded as infinitely far away from the camera.
[Rotation matching using the least-squares method](https://lisyarus.github.io/blog/posts/3d-shape-matching-with-quaternions.html) can be performed by clicking corresponding points that can be regarded as infinitely far away from the camera.

```shell
v1c lr left.jpg right.jpg --automatch gui
Expand All @@ -114,6 +103,13 @@ You can also specify the corresponding points manually:
v1c lr left.jpg right.jpg --automatch "0,0;0,0;1,1;1,1" # left_x1,left_y1;right_x1,right_y1;...
```

$$
a_k, b_k \in \mathbb{R}^3,
\min_{R \in SO(3)} \sum_k \|\|R a_k - b_k\|\|^2
$$

### Anaglyph

`--merge` option (which exports as [anaglyph](https://en.wikipedia.org/wiki/Anaglyph_3D) image) can be used to check if the calibration is successful by checking if the infinitely far points are overlapped.

```shell
Expand All @@ -122,12 +118,25 @@ v1c lr left.jpg right.jpg --automatch gui --merge

### Swap

If the camera is mounted upside down, you can swap the left and right images for conversion:
If the camera is mounted upside down, you can simply use the `--swap` option without changing the transformer or other parameters:

```shell
v1c lr left.jpg right.jpg --swap
```

### Custom conversion model

You can also specify the conversion model by adding Python code directly to the `--transformer` option:

```shell
v1c lr left.jpg right.jpg --transformer 'EquirectangularEncoder() * Euclidean3DRotator(from_rotation_vector([0, np.pi / 4, 0])) * FisheyeDecoder("equidistant")'
```

If tuple, the first transformer is applied to the left image and the second transformer is applied to the right image. If a single transformer is given, it is applied to both images.

Please refer to the [API documentation](https://vr180-convert.readthedocs.io/) for the available transformers and their parameters.
For `from_rotation_vector`, please refer to the [numpy-quaternion documentation](https://quaternion.readthedocs.io/en/latest/Package%20API%3A/quaternion/#from_rotation_vector).

### Single image conversion

To convert a single image, use `v1c s` instead.
Expand Down Expand Up @@ -159,11 +168,38 @@ transformer = EquirectangularEncoder() * MyTransformer() * FisheyeDecoder("equid
apply_lr(transformer, left_path="left.jpg", right_path="right.jpg", out_path="output.jpg")
```

## How to edit images
## Tips

### How to determine which image is left or right

<!--
- In the left image, the subject faces more to the right.
- In the right image, the subject faces more to the left.
- In other words, in a SBS image, the subject is oriented toward the center.
In anaglyph images,
- The left eye is covered with a red film, so the portion for the left eye is shown in blue.
- The right eye is covered with a blue film, so the portion for the right eye is shown in red.
| Film Color | <span style="color:red">Red</span> | <span style="color:blue">Blue</span> |
| Anaglyph Color | <span style="color:blue">Blue</span> | <span style="color:red">Red</span> |
-->

| | Left | Right |
| ------------------- | --------------------------- | --------------------------- |
| Subject Orientation | Right | Left |
| Film Color | ${\color{red}\text{Red}}$ | ${\color{blue}\text{Blue}}$ |
| Anaglyph Color | ${\color{blue}\text{Blue}}$ | ${\color{red}\text{Red}}$ |

- In a SBS image, the subject is oriented toward the center.

### How to edit images

This program cannot read RAW files. To deal with white-outs, etc., it is required to process each image with a program such as Photoshop, Lightroom, [RawTherapee](https://rawtherapee.com/downloads/), [Darktable](https://www.darktable.org/install/), etc.

This program cannot read RAW files. To deal with white-outs, etc., it is recommended to process the image in Photoshop or other software first.
However, this is so exhaustive, so it is recommended to take the images with jpeg format, being careful not to overexpose the images, and convert them with this program, then use Lightroom, [RawTherapee](https://rawtherapee.com/downloads/), [Darktable](https://www.darktable.org/install/) or other software to adjust colors and exposure, etc.

### Example of processing in Photoshop
#### Example of processing in Photoshop (Exquisite editing)

1. Open one of the images just for specifying the canvas size.
2. Add each image as Smart Objects (`LRaw`, `RRaw`) and make **minimal** corrections to match the exposure using `Camera Raw Filter`.
Expand Down
18 changes: 9 additions & 9 deletions src/vr180_convert/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ def lr(
_InterpolationFlags,
typer.Option(help="Interpolation method, defaults to lanczos4"),
] = _InterpolationFlags.INTER_LANCZOS4, # type: ignore
boarder_mode: Annotated[
border_mode: Annotated[
_BorderTypes, typer.Option(help="Border mode, defaults to constant")
] = _BorderTypes.BORDER_CONSTANT, # type: ignore
boarder_value: int = 0,
border_value: int = 0,
radius: Annotated[
str, typer.Option(help="Radius of the fisheye image, defaults to 'auto'")
] = "auto",
Expand Down Expand Up @@ -265,9 +265,9 @@ def lr(
)
LOG.info(f"Automatched transformer: {transformer_}")

if swap:
if isinstance(transformer_, tuple):
transformer_ = transformer_[1], transformer_[0]
# if swap:
# if isinstance(transformer_, tuple) and automatch == "":
# transformer_ = transformer_[1], transformer_[0]

# apply transformer
name_unique_content = (
Expand All @@ -279,8 +279,8 @@ def lr(
transformer,
size,
interpolation,
boarder_mode,
str(boarder_value),
border_mode,
str(border_value),
radius,
str(merge),
str(autosearch_timestamp_calib_r_earlier_l),
Expand Down Expand Up @@ -308,8 +308,8 @@ def lr(
radius=float(radius) if radius not in ["auto", "max"] else radius, # type: ignore
size_output=tuple(map(int, size.split("x"))), # type: ignore
interpolation=getattr(cv, interpolation.upper()),
boarder_mode=getattr(cv, boarder_mode.upper()),
boarder_value=boarder_value,
boarder_mode=getattr(cv, border_mode.upper()),
boarder_value=border_value,
merge=merge,
)

Expand Down

0 comments on commit 2aa7951

Please sign in to comment.