Skip to content

Commit 4c6afd2

Browse files
committed
image to chars + google slides script
1 parent 5ec4591 commit 4c6afd2

File tree

6 files changed

+157
-56
lines changed

6 files changed

+157
-56
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
*.pyc
22
tests/
33
.vscode/
4-
.idea/
4+
.idea/
5+
6+
secrets/
Lines changed: 28 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
1-
#%% [markdown]
21
# # Image to chars
32
# We want to represent images with chars to get a cool matrix effect
43
#
5-
# All data that we are working on can be found here: https://github.com/YoniChechik/AI_is_Math/tree/master/other_tutorials
4+
# All data that we are working on can be found here: https://github.com/YoniChechik/AI_is_Math
65

7-
#%%
8-
import numpy as np
96
import cv2
107
import matplotlib.pyplot as plt
8+
import numpy as np
9+
from PIL import Image, ImageDraw, ImageFont
1110

12-
#%%
13-
im_bgr = cv2.imread("matrix.jpg")
11+
im_bgr = cv2.imread("image_to_chars/matrix.jpg")
1412
im_rgb = cv2.cvtColor(im_bgr, cv2.COLOR_BGR2RGB)
1513

1614
plt.imshow(im_rgb)
1715
plt.title("Wanted result style")
1816
plt.show()
1917

20-
21-
#%% [markdown]
2218
# Let's read an image to start and experiment on
23-
im_bgr = cv2.imread("person.jpg")
19+
im_bgr = cv2.imread("image_to_chars/person.jpg")
2420
im_rgb = cv2.cvtColor(im_bgr, cv2.COLOR_BGR2RGB)
2521

2622
plt.imshow(im_rgb)
2723
plt.title("original image")
2824
plt.show()
2925

30-
31-
#%% [markdown]
3226
# Start with 2 functions to convert chars to pixel array representation
3327
# You don't really need to understand it, we simply copy it from the web...
34-
#%%
35-
from PIL import Image
36-
from PIL import ImageFont
37-
from PIL import ImageDraw
38-
import string
28+
29+
30+
def max_char_window_size(char_list, font_path, fontsize):
31+
font = ImageFont.truetype(font_path, fontsize)
32+
max_w = max_h = 0
33+
for c in char_list:
34+
_, _, w, h = font.getbbox(c)
35+
if w > max_w:
36+
max_w = w
37+
if h > max_h:
38+
max_h = h
39+
return max_w, max_h
3940

4041

4142
def char_to_pixels(text, window_size_wh, font_path, fontsize):
@@ -52,34 +53,19 @@ def char_to_pixels(text, window_size_wh, font_path, fontsize):
5253
return arr
5354

5455

55-
def max_char_window_size(font_path, fontsize):
56-
font = ImageFont.truetype(font_path, fontsize)
57-
max_w = max_h = 0
58-
for c in string.printable[:-5]:
59-
w, h = font.getsize(c)
60-
if w > max_w:
61-
max_w = w
62-
if h > max_h:
63-
max_h = h
64-
return max_w, max_h
65-
66-
67-
#%% [markdown]
6856
# Next we will build the chars we want to use for the image representation.
69-
#%%
7057
# download the font from here: https://github.com/YoniChechik/AI_is_Math/tree/master/other_tutorials
71-
FONT_PATH = "whitrabt.ttf"
58+
FONT_PATH = "image_to_chars/whitrabt.ttf"
7259
FONT_SIZE = 14
73-
REPRESENTATION_CHARS = [" ", ".", ":", "!", "+", "*", "e", "$", "@"]
60+
REPRESENTATION_CHARS = [" ", ".", ":", "+", "*", "e", "$", "@"]
7461

75-
76-
window_size_wh = max_char_window_size(FONT_PATH, FONT_SIZE)
62+
window_size_wh = max_char_window_size(REPRESENTATION_CHARS, FONT_PATH, FONT_SIZE)
7763

7864
char_pix_list = []
7965
for c in REPRESENTATION_CHARS:
8066
char_pix_list.append(char_to_pixels(c, window_size_wh, FONT_PATH, FONT_SIZE))
8167

82-
#%%
68+
8369
def display(arr):
8470
result = np.where(arr, "#", " ")
8571
print("\n".join(["".join(row) for row in result]))
@@ -89,29 +75,23 @@ def display(arr):
8975
print(c)
9076
display(c_pix)
9177

92-
#%% [markdown]
9378
# This is the tricky part...
9479
# Each small block of the image should be represented as the closest char from our list.
9580
# By doing decimation on the graylevel image we can get the *mean intensity of the block*,
9681
# and then we can convert it to a char that corresponds to this intensity.
97-
#%%
9882
w = window_size_wh[0]
9983
h = window_size_wh[1]
10084

101-
10285
im_gray = cv2.cvtColor(im_bgr, cv2.COLOR_BGR2GRAY)
10386
im_resize = cv2.resize(im_gray, (im_gray.shape[1] // w, im_gray.shape[0] // h))
10487

105-
10688
plt.imshow(im_resize)
10789
plt.colorbar()
10890
plt.title("resized gray image")
10991
plt.show()
11092

111-
#%% [markdown]
11293
# Each block now has a corresponding number to our `REPRESENTATION_CHARS`
11394
# LUT = look-up table
114-
#%%
11595
quantization_step = 256 / len(REPRESENTATION_CHARS)
11696
im_lut = np.floor(im_resize / quantization_step).astype(int)
11797

@@ -120,24 +100,22 @@ def display(arr):
120100
plt.title("LUT representation of the image")
121101
plt.show()
122102

123-
#%% [markdown]
124103
# Now simply build a new image block by block from our `im_lut`
125-
#%%
126104
res = np.zeros((im_lut.shape[0] * h, im_lut.shape[1] * w))
127105

128106
for col in range(im_lut.shape[0]):
129107
for row in range(im_lut.shape[1]):
130-
131-
res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[im_lut[col, row]]
108+
res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[
109+
im_lut[col, row]
110+
]
132111

133112
plt.imshow(res)
134113
plt.title("Final result")
135114
plt.show()
136115

137-
#%% [markdown]
116+
138117
# Building our entire code as a function and running it on a video stream.
139118
# (This will not work in google colab, only in your own computer with a camera)
140-
#%%
141119
def im_to_chars(im_bgr, char_pix_list, window_size_wh):
142120
w = window_size_wh[0]
143121
h = window_size_wh[1]
@@ -152,20 +130,19 @@ def im_to_chars(im_bgr, char_pix_list, window_size_wh):
152130

153131
for col in range(im_lut.shape[0]):
154132
for row in range(im_lut.shape[1]):
155-
156-
res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[im_lut[col, row]]
133+
res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[
134+
im_lut[col, row]
135+
]
157136

158137
return res
159138

160139

161-
# %%
162140
cap = cv2.VideoCapture(0)
163141

164142
# Check if camera was opened correctly
165143
if not (cap.isOpened()):
166144
print("Could not open video device")
167145

168-
169146
# Set the resolution
170147
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
171148
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
@@ -187,7 +164,3 @@ def im_to_chars(im_bgr, char_pix_list, window_size_wh):
187164
# When everything done, release the capture
188165
cap.release()
189166
cv2.destroyAllWindows()
190-
191-
#%% [markdown]
192-
# ## BONUS
193-
# Try at home to add color from the original image to the char representation
File renamed without changes.
File renamed without changes.
File renamed without changes.

slides.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"""
2+
Create or Select a Project in Google Cloud Console:
3+
4+
Go to the Google Cloud Console.
5+
If you haven't already created a project, you will need to create one. Otherwise, select an existing project.
6+
7+
Enable the Google Drive API:
8+
In the dashboard of your project, navigate to the "APIs & Services > Library".
9+
Search for "Google Drive API" and select it.
10+
Click "Enable" to enable the Google Drive API for your project.
11+
12+
Create Credentials:
13+
After enabling the API, go to "APIs & Services > Credentials".
14+
Click "Create Credentials" at the top of the page.
15+
Choose “OAuth client ID”.
16+
17+
Configure the OAuth consent screen:
18+
You'll be prompted to configure the OAuth consent screen before creating credentials. This is the screen that users will see when they authenticate with your application.
19+
Make sure to add a test user that is your mail.
20+
21+
Create OAuth 2.0 Client ID:
22+
After configuring the consent screen, you’ll be taken back to the "Create credentials" screen.
23+
For "Application type", select "Web application" or another type relevant to your application.
24+
Set a name for the OAuth 2.0 client.
25+
Under "Authorized redirect URIs", add http://localhost:8080/.
26+
Click “Create”.
27+
Download the Credentials:
28+
29+
credentials.json
30+
After creating the client ID, you'll see a confirmation screen showing your client ID and client secret.
31+
Click the download button (it looks like a download icon) to download the JSON file containing your credentials.
32+
Rename this file to credentials.json and place it in the directory of your Python script.
33+
34+
Install Required Libraries:
35+
If you haven’t installed the required libraries for the Google API client and OAuth, you can install them via pip:
36+
37+
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
38+
"""
39+
40+
41+
import io
42+
import os
43+
44+
from google.auth.transport.requests import Request
45+
from google.oauth2.credentials import Credentials
46+
from google_auth_oauthlib.flow import InstalledAppFlow
47+
from googleapiclient.discovery import build
48+
from googleapiclient.http import MediaIoBaseDownload
49+
50+
51+
def get_credentials():
52+
scopes = ["https://www.googleapis.com/auth/drive"]
53+
54+
creds = None
55+
# The file token.json stores the user's access and refresh tokens.
56+
if os.path.exists("secrets/token.json"):
57+
creds = Credentials.from_authorized_user_file("secrets/token.json", scopes)
58+
# If there are no (valid) credentials available, let the user log in.
59+
if not creds or not creds.valid:
60+
if creds and creds.expired and creds.refresh_token:
61+
creds.refresh(Request())
62+
else:
63+
assert os.path.isfile(
64+
"secrets/credentials.json"
65+
), "You need secrets/credentials.json. Download it from client secrets in: https://console.cloud.google.com/apis/credentials/oauthclient/385659825496-0123vosqnmabsha0bkdfahktrhqg5d8v.apps.googleusercontent.com?project=slides-to-pdf-412609"
66+
flow = InstalledAppFlow.from_client_secrets_file(
67+
"secrets/credentials.json", scopes
68+
)
69+
creds = flow.run_local_server(port=8080)
70+
# Save the credentials for the next run
71+
with open("secrets/token.json", "w") as token:
72+
token.write(creds.to_json())
73+
return creds
74+
75+
76+
def download_as_pdf(service, file_id, output_filename):
77+
request = service.files().export_media(fileId=file_id, mimeType="application/pdf")
78+
fh = io.BytesIO()
79+
downloader = MediaIoBaseDownload(fh, request)
80+
done = False
81+
while done is False:
82+
status, done = downloader.next_chunk()
83+
print("Download %d%%." % int(status.progress() * 100))
84+
85+
with open(output_filename, "wb") as f:
86+
f.write(fh.getbuffer())
87+
88+
89+
# Load credentials
90+
creds = Credentials.from_authorized_user_file("secrets/token.json")
91+
service = build("drive", "v3", credentials=creds)
92+
93+
94+
def find_file_id_by_path(service, path):
95+
folder_id = "root" # start from the root
96+
for name in path.split("/"):
97+
if not name:
98+
continue
99+
query = f"name='{name}' and '{folder_id}' in parents"
100+
response = (
101+
service.files()
102+
.list(
103+
q=query, spaces="drive", fields="files(id, name, mimeType)", pageSize=10
104+
)
105+
.execute()
106+
)
107+
108+
files = response.get("files", [])
109+
110+
if not files:
111+
raise Exception(f"No such file/dir named {name} in path {path}")
112+
113+
# Assuming the first found file/folder is the correct one
114+
folder_id = files[0]["id"]
115+
116+
return folder_id
117+
118+
119+
if __name__ == "__main__":
120+
path = "CV Course/slides/Intro to Computer Vision"
121+
122+
creds = get_credentials()
123+
service = build("drive", "v3", credentials=creds)
124+
125+
file_id = find_file_id_by_path(service, path)
126+
download_as_pdf(service, file_id, "output2.pdf")

0 commit comments

Comments
 (0)