Skip to content

Commit

Permalink
image to chars + google slides script
Browse files Browse the repository at this point in the history
  • Loading branch information
YoniChechik committed Jan 29, 2024
1 parent 5ec4591 commit 4c6afd2
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 56 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
*.pyc
tests/
.vscode/
.idea/
.idea/

secrets/
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
#%% [markdown]
# # Image to chars
# We want to represent images with chars to get a cool matrix effect
#
# All data that we are working on can be found here: https://github.com/YoniChechik/AI_is_Math/tree/master/other_tutorials
# All data that we are working on can be found here: https://github.com/YoniChechik/AI_is_Math

#%%
import numpy as np
import cv2
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image, ImageDraw, ImageFont

#%%
im_bgr = cv2.imread("matrix.jpg")
im_bgr = cv2.imread("image_to_chars/matrix.jpg")
im_rgb = cv2.cvtColor(im_bgr, cv2.COLOR_BGR2RGB)

plt.imshow(im_rgb)
plt.title("Wanted result style")
plt.show()


#%% [markdown]
# Let's read an image to start and experiment on
im_bgr = cv2.imread("person.jpg")
im_bgr = cv2.imread("image_to_chars/person.jpg")
im_rgb = cv2.cvtColor(im_bgr, cv2.COLOR_BGR2RGB)

plt.imshow(im_rgb)
plt.title("original image")
plt.show()


#%% [markdown]
# Start with 2 functions to convert chars to pixel array representation
# You don't really need to understand it, we simply copy it from the web...
#%%
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import string


def max_char_window_size(char_list, font_path, fontsize):
font = ImageFont.truetype(font_path, fontsize)
max_w = max_h = 0
for c in char_list:
_, _, w, h = font.getbbox(c)
if w > max_w:
max_w = w
if h > max_h:
max_h = h
return max_w, max_h


def char_to_pixels(text, window_size_wh, font_path, fontsize):
Expand All @@ -52,34 +53,19 @@ def char_to_pixels(text, window_size_wh, font_path, fontsize):
return arr


def max_char_window_size(font_path, fontsize):
font = ImageFont.truetype(font_path, fontsize)
max_w = max_h = 0
for c in string.printable[:-5]:
w, h = font.getsize(c)
if w > max_w:
max_w = w
if h > max_h:
max_h = h
return max_w, max_h


#%% [markdown]
# Next we will build the chars we want to use for the image representation.
#%%
# download the font from here: https://github.com/YoniChechik/AI_is_Math/tree/master/other_tutorials
FONT_PATH = "whitrabt.ttf"
FONT_PATH = "image_to_chars/whitrabt.ttf"
FONT_SIZE = 14
REPRESENTATION_CHARS = [" ", ".", ":", "!", "+", "*", "e", "$", "@"]
REPRESENTATION_CHARS = [" ", ".", ":", "+", "*", "e", "$", "@"]


window_size_wh = max_char_window_size(FONT_PATH, FONT_SIZE)
window_size_wh = max_char_window_size(REPRESENTATION_CHARS, FONT_PATH, FONT_SIZE)

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

#%%

def display(arr):
result = np.where(arr, "#", " ")
print("\n".join(["".join(row) for row in result]))
Expand All @@ -89,29 +75,23 @@ def display(arr):
print(c)
display(c_pix)

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


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


plt.imshow(im_resize)
plt.colorbar()
plt.title("resized gray image")
plt.show()

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

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

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

for col in range(im_lut.shape[0]):
for row in range(im_lut.shape[1]):

res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[im_lut[col, row]]
res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[
im_lut[col, row]
]

plt.imshow(res)
plt.title("Final result")
plt.show()

#%% [markdown]

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

for col in range(im_lut.shape[0]):
for row in range(im_lut.shape[1]):

res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[im_lut[col, row]]
res[col * h : col * h + h, row * w : row * w + w] = char_pix_list[
im_lut[col, row]
]

return res


# %%
cap = cv2.VideoCapture(0)

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


# Set the resolution
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
Expand All @@ -187,7 +164,3 @@ def im_to_chars(im_bgr, char_pix_list, window_size_wh):
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

#%% [markdown]
# ## BONUS
# 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.
126 changes: 126 additions & 0 deletions slides.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
"""
Create or Select a Project in Google Cloud Console:
Go to the Google Cloud Console.
If you haven't already created a project, you will need to create one. Otherwise, select an existing project.
Enable the Google Drive API:
In the dashboard of your project, navigate to the "APIs & Services > Library".
Search for "Google Drive API" and select it.
Click "Enable" to enable the Google Drive API for your project.
Create Credentials:
After enabling the API, go to "APIs & Services > Credentials".
Click "Create Credentials" at the top of the page.
Choose “OAuth client ID”.
Configure the OAuth consent screen:
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.
Make sure to add a test user that is your mail.
Create OAuth 2.0 Client ID:
After configuring the consent screen, you’ll be taken back to the "Create credentials" screen.
For "Application type", select "Web application" or another type relevant to your application.
Set a name for the OAuth 2.0 client.
Under "Authorized redirect URIs", add http://localhost:8080/.
Click “Create”.
Download the Credentials:
credentials.json
After creating the client ID, you'll see a confirmation screen showing your client ID and client secret.
Click the download button (it looks like a download icon) to download the JSON file containing your credentials.
Rename this file to credentials.json and place it in the directory of your Python script.
Install Required Libraries:
If you haven’t installed the required libraries for the Google API client and OAuth, you can install them via pip:
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
"""


import io
import os

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaIoBaseDownload


def get_credentials():
scopes = ["https://www.googleapis.com/auth/drive"]

creds = None
# The file token.json stores the user's access and refresh tokens.
if os.path.exists("secrets/token.json"):
creds = Credentials.from_authorized_user_file("secrets/token.json", scopes)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
assert os.path.isfile(
"secrets/credentials.json"
), "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"
flow = InstalledAppFlow.from_client_secrets_file(
"secrets/credentials.json", scopes
)
creds = flow.run_local_server(port=8080)
# Save the credentials for the next run
with open("secrets/token.json", "w") as token:
token.write(creds.to_json())
return creds


def download_as_pdf(service, file_id, output_filename):
request = service.files().export_media(fileId=file_id, mimeType="application/pdf")
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
status, done = downloader.next_chunk()
print("Download %d%%." % int(status.progress() * 100))

with open(output_filename, "wb") as f:
f.write(fh.getbuffer())


# Load credentials
creds = Credentials.from_authorized_user_file("secrets/token.json")
service = build("drive", "v3", credentials=creds)


def find_file_id_by_path(service, path):
folder_id = "root" # start from the root
for name in path.split("/"):
if not name:
continue
query = f"name='{name}' and '{folder_id}' in parents"
response = (
service.files()
.list(
q=query, spaces="drive", fields="files(id, name, mimeType)", pageSize=10
)
.execute()
)

files = response.get("files", [])

if not files:
raise Exception(f"No such file/dir named {name} in path {path}")

# Assuming the first found file/folder is the correct one
folder_id = files[0]["id"]

return folder_id


if __name__ == "__main__":
path = "CV Course/slides/Intro to Computer Vision"

creds = get_credentials()
service = build("drive", "v3", credentials=creds)

file_id = find_file_id_by_path(service, path)
download_as_pdf(service, file_id, "output2.pdf")

0 comments on commit 4c6afd2

Please sign in to comment.