Skip to content

Commit 009bd49

Browse files
Merge pull request #2 from Robot-Wranglers/mainline
refactor; demo.py -> imgrot.py
2 parents bc2cac5 + 0438a6d commit 009bd49

File tree

9 files changed

+125
-116
lines changed

9 files changed

+125
-116
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ RUN apt-get update && apt-get -y install python3-dev python3-pip chafa imagemagi
55
RUN mkdir /opt/imgrot
66
COPY . /opt/imgrot
77
RUN pip3 install -r /opt/imgrot/requirements.txt --break-system-packages
8-
ENTRYPOINT [ "python3", "/opt/imgrot/demo.py" ]
8+
ENTRYPOINT [ "python3", "/opt/imgrot/imgrot.py" ]

Makefile

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,19 @@ clean: docker.clean py-clean
2626
docs: docs.vhs docs.jinja #docs.rotations
2727
docs.jinja:
2828
${pynchon.run} jinja render README.md.j2
29-
python demo.py img/icon.png --stream > img/demo.gif
29+
python imgrot.py img/icon.png --stream > img/demo.gif
3030
docs.vhs:; PS1="$$ " sh -c "${pynchon.run} vhs apply"
3131
docs.rotations:
32-
python demo.py img/graph.png --bg lightblue --rotation x --stream > img/rx.gif
33-
python demo.py img/graph.png --bg lightblue --rotation y --stream > img/ry.gif
34-
python demo.py img/graph.png --bg lightblue --rotation s --stream > img/rs.gif
35-
python demo.py img/graph.png --bg lightblue --rotation j --stream > img/rj.gif
36-
python demo.py img/graph.png --bg lightblue --rotation w --stream > img/rw.gif
37-
python demo.py img/graph.png --bg lightblue --rotation f --stream > img/rf.gif
38-
python demo.py img/graph.png --bg lightblue --rotation exit-ul --stream > img/rul.gif
39-
python demo.py img/graph.png --bg lightblue --rotation exit-ur --stream > img/rur.gif
40-
python demo.py img/graph.png --bg lightblue --rotation exit-lr --stream > img/rlr.gif
41-
python demo.py img/graph.png --bg lightblue --rotation exit-ll --stream > img/rll.gif
32+
python imgrot.py img/graph.png --bg lightblue --rotation x --stream > img/rx.gif
33+
python imgrot.py img/graph.png --bg lightblue --rotation y --stream > img/ry.gif
34+
python imgrot.py img/graph.png --bg lightblue --rotation s --stream > img/rs.gif
35+
python imgrot.py img/graph.png --bg lightblue --rotation j --stream > img/rj.gif
36+
python imgrot.py img/graph.png --bg lightblue --rotation w --stream > img/rw.gif
37+
python imgrot.py img/graph.png --bg lightblue --rotation f --stream > img/rf.gif
38+
python imgrot.py img/graph.png --bg lightblue --rotation exit-ul --stream > img/rul.gif
39+
python imgrot.py img/graph.png --bg lightblue --rotation exit-ur --stream > img/rur.gif
40+
python imgrot.py img/graph.png --bg lightblue --rotation exit-lr --stream > img/rlr.gif
41+
python imgrot.py img/graph.png --bg lightblue --rotation exit-ll --stream > img/rll.gif
4242

4343

4444
docker.clean:

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
<tr>
44
<td colspan=2><strong>
55
imgrot
6-
</strong>&nbsp;&nbsp;&nbsp;&nbsp;
6+
</strong><br/>
7+
<a href="https://hub.docker.com/r/robotwranglers/imgrot"><img src="https://img.shields.io/badge/dockerhub-imgrot-blue"><img src="https://img.shields.io/docker/v/robotwranglers/imgrot"></a>
78
</td>
89
</tr>
910
<tr>
@@ -17,7 +18,6 @@
1718
</tr>
1819
</table>
1920
</P>
20-
<a href="https://hub.docker.com/r/robotwranglers/imgrot"><img src="https://img.shields.io/badge/dockerhub--blue.svg?logo=Docker"></a>
2121

2222
-------------------------------------
2323

@@ -27,7 +27,7 @@ A fork / update for the excellent original work at [eborboihuc/rotate_3d](https:
2727

2828
The original uses `opencv` to rotate 2d -> 3d. This version adds better CLI parsing, support for python3, newer opencv, ability to animate and render animations with `ffmpeg`, and works via docker.
2929

30-
Besides creating gifs, it can display them inside a terminal, using [chafa](https://github.com/hpjansson/chafa).
30+
Different kinds of rotation are supported as well (see the end of this page for [a gallery](#changing-axis-of-rotation)). Besides creating gifs, it can display them inside a terminal, using [chafa](https://github.com/hpjansson/chafa).
3131

3232
See also [the original docs](docs/README.original.md)
3333

@@ -48,7 +48,7 @@ pip install -r requirements.txt
4848
**Basic usage info follows:**
4949

5050
```bash
51-
Usage: demo.py [OPTIONS] IMG_PATH
51+
Usage: imgrot.py [OPTIONS] IMG_PATH
5252

5353
Options:
5454
--bg TEXT Background color to pass to chafa
@@ -78,7 +78,7 @@ You can also set `LOGLEVEL=debug` for more info.
7878
7979
A few examples of usage from docker:
8080
81-
**Saving an animated gif to a file:**
81+
#### Saving an Animation
8282
8383
```bash
8484
$ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot img/icon.png --range 360 --img-shape 200x200 --stream > demo.gif
@@ -88,7 +88,7 @@ $ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot im
8888
<img width=25% align=center src=img/demo.gif>
8989
</p>
9090
91-
**Rendering a gif, then displaying it in a terminal-friendly way with chafa:**
91+
#### Terminal-Friendly Display
9292
9393
```bash
9494
$ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot img/icon.png --display --stretch --bg lightblue
@@ -98,11 +98,11 @@ $ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot im
9898
<img width=50% align=center src=img/demo.chafa.gif>
9999
</p>
100100
101-
Note that this tries to respect transparency in the original image, but for more contrast you can effectively add highlights by passing '--bg' arguments that go through to chafa.
101+
Note that this tries to respect transparency in the original image, but for more contrast with black images on black terminals, you can effectively add highlights by passing '--bg' arguments that go through to chafa.
102102
103103
------------------------------
104104
105-
**Changing axis of rotation**
105+
#### Changing Axis of Rotation
106106
107107
The rotation can be controlled to create a bunch of different effects:
108108

README.md.j2

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
<tr>
44
<td colspan=2><strong>
55
imgrot
6-
</strong>&nbsp;&nbsp;&nbsp;&nbsp;
6+
</strong><br/>
7+
<a href="{{dockerhub.repo_url}}"><img src="https://img.shields.io/badge/dockerhub-imgrot-blue"><img src="https://img.shields.io/docker/v/robotwranglers/imgrot"></a>
78
</td>
89
</tr>
910
<tr>
@@ -17,7 +18,6 @@
1718
</tr>
1819
</table>
1920
</P>
20-
<a href="{{dockerhub.repo_url}}"><img src="https://img.shields.io/badge/dockerhub--blue.svg?logo=Docker"></a>
2121

2222
-------------------------------------
2323

@@ -27,7 +27,7 @@ A fork / update for the excellent original work at [eborboihuc/rotate_3d](https:
2727

2828
The original uses `opencv` to rotate 2d -> 3d. This version adds better CLI parsing, support for python3, newer opencv, ability to animate and render animations with `ffmpeg`, and works via docker.
2929

30-
Besides creating gifs, it can display them inside a terminal, using [chafa](https://github.com/hpjansson/chafa).
30+
Different kinds of rotation are supported as well (see the end of this page for [a gallery](#changing-axis-of-rotation)). Besides creating gifs, it can display them inside a terminal, using [chafa](https://github.com/hpjansson/chafa).
3131

3232
See also [the original docs](docs/README.original.md)
3333

@@ -48,7 +48,7 @@ pip install -r requirements.txt
4848
**Basic usage info follows:**
4949

5050
```bash
51-
{{bash('python demo.py --help')}}
51+
{{bash('python imgrot.py --help')}}
5252
```
5353

5454
You can also set `LOGLEVEL=debug` for more info.
@@ -59,7 +59,7 @@ You can also set `LOGLEVEL=debug` for more info.
5959

6060
A few examples of usage from docker:
6161

62-
**Saving an animated gif to a file:**
62+
#### Saving an Animation
6363

6464
```bash
6565
$ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot img/icon.png --range 360 --img-shape 200x200 --stream > demo.gif
@@ -69,7 +69,7 @@ $ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot im
6969
<img width=25% align=center src=img/demo.gif>
7070
</p>
7171

72-
**Rendering a gif, then displaying it in a terminal-friendly way with chafa:**
72+
#### Terminal-Friendly Display
7373

7474
```bash
7575
$ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot img/icon.png --display --stretch --bg lightblue
@@ -79,11 +79,11 @@ $ docker run -it --rm -v `pwd`:/workspace -w /workspace robotwranglers/imgrot im
7979
<img width=50% align=center src=img/demo.chafa.gif>
8080
</p>
8181

82-
Note that this tries to respect transparency in the original image, but for more contrast you can effectively add highlights by passing '--bg' arguments that go through to chafa.
82+
Note that this tries to respect transparency in the original image, but for more contrast with black images on black terminals, you can effectively add highlights by passing '--bg' arguments that go through to chafa.
8383

8484
------------------------------
8585

86-
**Changing axis of rotation**
86+
#### Changing Axis of Rotation
8787

8888
The rotation can be controlled to create a bunch of different effects:
8989

docs/README.original.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Rotate along XZ axis
1919
Change main function with ideal [arguments](#parameters)
2020

2121
```bash
22-
python demo.py [path of the image] [degree to rotate] ([ideal width] [ideal height])
22+
python imgrot.py [path of the image] [degree to rotate] ([ideal width] [ideal height])
2323
```
2424
e.g.,
2525
Example of rotating an image along yz-axis from 0 to 360 degree with a 5 pixel shift in +X direction
@@ -32,7 +32,7 @@ Example of rotating an image along yz-axis from 0 to 360 degree with a 5 pixel s
3232
```
3333
Then
3434
```bash
35-
python demo.py img/000001.jpg 360
35+
python imgrot.py img/000001.jpg 360
3636
```
3737

3838
## Parameters:

docs/tape/demo.tape

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Set Height 800
99
Set TypingSpeed .05
1010
Set PlaybackSpeed 1
1111
Set CursorBlink false
12-
Type "python demo.py img/icon.png --display --stretch --bg lightblue"
12+
Type "python imgrot.py img/icon.png --display --stretch --bg lightblue"
1313
Sleep 1.1
1414
Enter
1515
Sleep 30

image_transformer.py

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
from math import pi
2-
3-
import cv2
4-
import numpy as np
5-
61
# Usage:
72
# Change main function with ideal arguments
83
# Then
@@ -25,6 +20,13 @@
2520
# 1. : http://stackoverflow.com/questions/17087446/how-to-calculate-perspective-transform-for-opencv-from-rotation-angles
2621
# 2. : http://jepsonsblog.blogspot.tw/2012/11/rotation-in-3d-using-opencvs.html
2722

23+
import math
24+
import random
25+
from math import pi
26+
27+
import cv2
28+
import numpy as np
29+
2830

2931
def get_rad(theta, phi, gamma):
3032
return (deg_to_rad(theta), deg_to_rad(phi), deg_to_rad(gamma))
@@ -43,29 +45,102 @@ def rad_to_deg(rad):
4345

4446

4547
class ImageTransformer:
46-
"""Perspective transformation class for image
47-
with shape (height, width, #channels)"""
48+
"""
49+
Perspective transformation class for image
50+
with shape (height, width, #channels)
51+
"""
4852

4953
def load_image(self, img_path, shape=None):
54+
""" """
5055
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
5156
if shape is not None:
5257
img = cv2.resize(img, shape)
5358
return img
5459

5560
def __init__(self, image_path, shape):
61+
""" """
5662
self.image_path = image_path
5763
self.image = self.load_image(image_path, shape)
5864

5965
self.height = self.image.shape[0]
6066
self.width = self.image.shape[1]
6167
self.num_channels = self.image.shape[2]
6268

69+
def get_rotation_args(self, rotation: str, ang: int):
70+
"""
71+
Generates the arguments used for 'rotate_along_axis'
72+
This takes a rotation-mode 'rotation' and an angle
73+
named 'ang' in (0 - rot_range), and is called from a loop.
74+
"""
75+
if rotation in ["y"]:
76+
# y-axis from 0-360 degree, 5 pixel shift in +X
77+
rotargs = dict(phi=ang, dx=5)
78+
elif rotation in ["x"]:
79+
rotargs = dict(gamma=ang)
80+
elif rotation in ["s", "swivel"]:
81+
# yz-axis from 0 to 360 degree
82+
rotargs = dict(phi=ang, gamma=ang)
83+
elif rotation in ["jitter", "j"]:
84+
rotargs = dict(
85+
dx=random.choice([5, 0, 10]),
86+
phi=random.choice([ang, -ang]),
87+
gamma=random.choice([0, ang, -ang]),
88+
)
89+
elif rotation in ["wobble", "w"]:
90+
rotargs = dict(
91+
dx=random.choice([0, 10, 30]),
92+
dy=random.choice([25, 0, 10]),
93+
phi=random.choice([ang, -ang, math.sin(ang)]),
94+
gamma=random.choice([ang, -ang]),
95+
)
96+
elif rotation in ["f", "flip"]:
97+
rotargs = dict(dx=ang, dy=-ang, phi=math.tan(ang), gamma=ang)
98+
elif rotation.startswith("q"):
99+
rotargs = dict(
100+
dx=random.choice([0, 5, 10]),
101+
dy=random.choice([25, 0, 10]),
102+
phi=random.choice([ang, -ang, math.sin(ang)]),
103+
gamma=random.choice([ang, -ang]),
104+
)
105+
elif rotation.startswith("exit"):
106+
direction = rotation.split("-")[1]
107+
if direction == "ul":
108+
rotargs = dict(
109+
dx=-ang,
110+
dy=-ang,
111+
)
112+
elif direction == "ur":
113+
rotargs = dict(
114+
dx=ang,
115+
dy=-ang,
116+
)
117+
elif direction == "lr":
118+
rotargs = dict(
119+
dx=ang,
120+
dy=ang,
121+
)
122+
elif direction == "ll":
123+
rotargs = dict(
124+
dx=-ang,
125+
dy=ang,
126+
)
127+
else:
128+
raise ValueError(f"unknown rotation: {rotation}")
129+
rotargs.update(phi=math.tan(ang), gamma=math.tan(ang))
130+
else:
131+
raise ValueError(f"Not sure how to perform rotation {rotation}")
132+
return rotargs
133+
63134
@staticmethod
64135
def save_image(img_path, img):
136+
"""
137+
Saves an output image
138+
This is usually one that's resulted from a rotation, i.e a single frame in a larger animation
139+
"""
65140
cv2.imwrite(img_path, img)
66141

67142
def rotate_along_axis(self, theta=0, phi=0, gamma=0, dx=0, dy=0, dz=0):
68-
"""Wrapper for rotating a image"""
143+
"""Returns the new image that results from rotating self.image"""
69144

70145
# Get radius of rotation along 3 axes
71146
rtheta, rphi, rgamma = get_rad(theta, phi, gamma)
@@ -78,13 +153,10 @@ def rotate_along_axis(self, theta=0, phi=0, gamma=0, dx=0, dy=0, dz=0):
78153

79154
# Get projection matrix
80155
mat = self.get_M(rtheta, rphi, rgamma, dx, dy, dz)
81-
82156
return cv2.warpPerspective(self.image.copy(), mat, (self.width, self.height))
83157

84-
""" Get Perspective Projection Matrix """
85-
86158
def get_M(self, theta, phi, gamma, dx, dy, dz):
87-
159+
"""Get Perspective Projection Matrix"""
88160
w = self.width
89161
h = self.height
90162
f = self.focal

img/demo.chafa.gif

-2.45 KB
Loading

0 commit comments

Comments
 (0)