WeChatに友達アバターフォトウォールを作ろう⁉️(笑)
皆さんこんにちは、タイニーミンです。
私は何年もWeChatを使っていますが、WeChatの友達のアバター用のピクチャーウォールを生成しようと思ったことはありますか?
例えば
注:アバターが重複していますが、これはローカルWeChatのアバターがそれほど多くないため、選択を繰り返さなければならないからです。WeChatの友達がたくさんいる人は、記事中に
np.random.choice(imgs, size=data.sum())
この行は、パラメータを追加するreplace=False
は、重複しないように選択できるようになります。
私と同じ考えのお友達がいたら、レッツゴー⏩ ?。
記事の目次
まず最初に、キャッシュされた WeChat アバターのリストを取得する必要があります。
???? WeChat アバターキャッシュリストを取得する ?
私たちがターゲットのアバターをタップして拡大表示すると、WeChat PCはそのアバターを
HDHeadImage
(HDHeadImage)ディレクトリに格納されます。
このターゲットは、pythonを介して直接読み込むことができます。
wechat_id = "Your microsignal"
path = os.path.expanduser(f"~/Documents/WeChat Files/{wechat_id}/FileStorage/General/HDHeadImage")
path
'C:\\Users\\\ASUS/Documents/WeChat Files/Your Microsign/FileStorage/General/HDHeadImage'
wechat_id
~/Documents
<ブロッククオート
/data/data/com.tencent.mm/MicroMsg
はマイクロ信号です。
avatar
WeChat ファイルのデフォルトの保存場所を変更していない場所によります。もし変更した場合は、変更したフォルダに変更する必要があります。
そうすると、そのフォルダの中にパソコンにあるアバターのHDキャッシュを見ることができます。
HD大画像キャッシュを読み込むと、WeChat PCのこの場所から読み込むことができます。
しかし、WeChatアバターのすべての小画像のキャッシュを取得したい場合はどうすればよいでしょうか。この時、WeChat PCから直接必要なデータを取得することはできませんが、root化された携帯電話の力を借りて、小型画像キャッシュ(ほぼ全ての小型画像キャッシュが含まれています)を取得することができます。
夜神月エミュレータを使い、夜神月エミュレータ経由で個人のWeChatにログイン後、もうしばらく訪問するとローカルにアバターキャッシュが生成されます。
次に、入力します。
everything
フォルダーに格納されます。
次に、最近変更された長い名前のフォルダに移動し、そこにある
from PIL import Image, ImageFont, ImageDraw, ImageChops
def create_text_img(text, size=30, fontname="msyhbd.ttc"):
"Author: Little Ming"
# Get the font object
font = ImageFont.truetype(fontname, size)
width = len(text) * size
# top left corner alignment draw text
im = Image.new(mode='RGBA', size=(width, size))
draw = ImageDraw.Draw(im=im)
w, h = draw.textsize(text, font)
o1, o2 = font.getoffset(text)
draw.text(xy=(-o1, -o2), text=text,
fill="black", font=font)
# Crop text excess space
bg = Image.new(mode='RGBA', size=im.size)
bbox = ImageChops.difference(im, bg).getbbox()
im = im.crop(bbox)
text_img = Image.new(mode='L', size=im.size, color=255)
text_img.paste(im, mask=im)
return text_img
display(create_text_img("friend avatar", fontname="STHUPO.TTF"))
display(create_text_img("buddy_avatar"))
フォルダには、すべてのアバターのキャッシュが格納されています。
<イグ
この時点で、イメージファイルをナイトメアエミュレータのAndroid共有パスにコピーすることで、PC上で読み込むことができます。
しかし、画像ファイルは個々のサブフォルダに入っているので、ここでは
import numpy as np
im = create_text_img("photo_wall", fontname="msyh.ttc")
data = np.array(im) ! = 255
h, w = data.shape
print(f"Total {data.sum()} images needed, width {w}, height {h}")
Total of 1115 images, 90 wide, 29 high
で目的のフォルダを検索し、その中の画像を一度に切り出すというものです。
抽出すると、次のようになります。
アバターパスの準備ができたので、テキストの描画を開始しましょう。
???? テキストパターンの描画⏩」。
テキストフォトウォールを作るには、テキストを描き出した後に写真を配置する場所を決めるために、ピクセルポイントを解析する必要があります。
ここでは、テキストの描画にやはりPILライブラリを使用し、デバッグを重ねた結果、以下のような描画方法を考案しました。
Photo Wall
中国語のアンバーとデフォルトのMicrosoft elegant boldで別々にテストするため。
⭐️テキストフォトウォールを描こう ?
テキストパターンのグレースケール画像オブジェクトを取得することで、テキストフォトウォールを簡単に描画することができます。
import os
img_path = r"C:\Users\ASUS\Nox_share\ImageShare\avatar"
imgs = os.listdir(img_path)
img_lists = np.random.choice(imgs, size=data.sum())
# Set the size of each avatar
size = 50
new_img = Image.new('RGB', (size * w, size * h), "white")
random_imgs = iter(img_lists)
for y, x in zip(*np.where(data)):
img_name = next(random_imgs)
src_img = Image.open(f'{img_path}/{img_name}')
src_img = src_img.resize((size, size), Image.ANTIALIAS)
# Copy the image to new_image
new_img.paste(src_img, (x * size, y * size))
new_img
私は
def create_picture_wall(data, imgs, size=50):
h, w = data.shape
random_imgs = iter(np.random.choice(imgs, size=data.sum()))
new_img = Image.new('RGB', (size * w, size * h), "white")
for y, x in zip(*np.where(data)):
img_name = next(random_imgs)
src_img = Image.open(f'{img_path}/{img_name}')
src_img = src_img.resize((size, size), Image.ANTIALIAS)
# Copy the image to new_image
new_img.paste(src_img, (x * size, y * size))
return new_img
をテキスト画像として使用し、合計1890枚のアバター画像を表示していますが、私のキャッシュフォルダにはそれほど多くの画像はなく、アバターを繰り返し選択できるようにする必要がありそうです。
ランダムなアバターリストを取得する。
im = create_text_img("小小明")
img_path = r"C:\Users\ASUS\Nox_share\ImageShare\avatar"
create_picture_wall(np.array(im) ! = 255, os.listdir(img_path))
im = create_text_img("小小明", fontname="msyh.ttc")
img_path = r"C:\Users\ASUS\Nox_share\ImageShare\avatar"
create_picture_wall(np.array(im) ! = 255, os.listdir(img_path))
すると、以下のようにアバターフォトウォールを生成することができます。
import math
import numpy as np
t = np.range(0, 2*math.pi, 0.1)
x = 16*np.sin(t)**3
y = 13*np.cos(t) - 5*np.cos(2*t) - 2*np.cos(3*t) - np.cos(4*t)
生成された結果。
このように、画像一覧のフォトウォールを生成することに成功したので、今後は中秋節、国慶節、バレンタインデーなどにそのまま利用することができます。フォトウォールの生成にはテキストだけでなく、特殊な形状の画像を使うこともあるので、今後のために、上記のロジックを以下のようにカプセル化します。
from matplotlib import pyplot as plt
plt.plot(x, y, color="r");
呼び出しの例
plt.fill(x+15, y+15, color="r");
<イグ
import math
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(-2, 2, 1000)
fx = np.sqrt(2*np.abs(x)-x**2)
gx = -2.14*np.sqrt(np.sqrt(2)-np.sqrt(np.abs(x)))
plt.plot(x, fx, color="r", label="upper")
plt.plot(x, gx, color="b", label="down")
plt.legend();
<イグ
❤️Pythonがハート模様を描く ?
ハート柄のフォトウォールを描くには、まずPILを使ってハート柄を描かなければなりません。ハートを描くための関数はいろいろあるので、以下、それぞれをデモして、まずはmatplotlibを使ってハート画像を実装してみます。
最もポピュラーなパラメトリック方程式は
x ( t ) = 16 罪 t 3 x(t)=16 {sin t}^3 <スパン x ( t ) <スパン = <スパン <スパン 1 <スパン 6 罪 <スパン t <スパン <スパン <スパン <スパン <スパン <スパン <スパン 3
<スパン <スパン y ( t ) = 13 コス t -t 5 コス 2 t -t 2 コス 3 t -cos コス 4 t y(t) = 13cos t- 5 Θcos 2t - 2 Θcos 3t - \cos 4t <スパン y ( t ) <スパン = <スパン <スパン 1 3 <スパン コス t <スパン <スパン - <スパン <スパン 5 <スパン コス 2 t <スパン <スパン - <スパン <スパン 2 <スパン コス 3 t <スパン <スパン - <スパン コス 4 t
このパラメトリック方程式はpythonで次のように表されます。
import math
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(-2, 2, 2000)
fx = np.sqrt(2*np.abs(x)-x**2)
gx = -2.14*np.sqrt(np.sqrt(2)-np.sqrt(np.abs(x)))
x = (x+2)*7.5
fx = (fx+2.5)*7.5
gx = (gx+2.5)*7.5
plt.plot(x, fx, color="r", label="upper")
plt.plot(x, gx, color="b", label="down")
plt.legend();
matplotlib を使えば、直接プロットすることができます。
plt.fill_between(x, gx, fx, color="r");
<イグ
x軸とy軸の両方にオフセットを加えて、0より大きい区間に入るようにします。
ハートの立体を作図します。
import math
from PIL import Image
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(-2, 2, 100)
fx = np.sqrt(2*np.abs(x)-x**2)
gx = -2.14*np.sqrt(np.sqrt(2)-np.sqrt(np.abs(x)))
fx = (fx+2.5)*7
gx = (gx+2.5)*7
fig = plt.figure()
plt.axis("off")
plt.fill_between(x, gx, fx, color="black")
fig.savefig("t.jpg");
<イグ
しかし、この形式のパラメトリック方程式では、境界の点座標が得られるだけで、PIL画像にプロットするための変換はまだ困難である。以下では、もう一つの不人気なハート型の関数方程式を使って、関数方程式を上下の2つの方程式からそれぞれ構成して、プロットしてみることにする。
上半分の式は f ( x ) = 2 ⋅ x 2 - x 2 f(x) = \sqrt{2}-x^{2}}. <スパン f ( x ) = <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン 2 <スパン ⋅ <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン x <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン 2 <スパン <スパン <スパン <スパン - <スパン x <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン 2 <スパン <スパン <スパン
方程式の下半分は g ( x ) = - 2.14 ⋅ 2 - ∣ x ∣ g(x) = -2.14 \sqrt{sqrt{2}} - ЪЪЪ <スパン g ( x ) = <スパン <スパン - 2 . 1 <スパン 4 <スパン ⋅ <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン <スパン 2 <スパン <スパン <スパン <スパン - <スパン <スパン <スパン <スパン <スパン <スパン <スパン ∣∣ x ∣ <スパン <スパン <スパン <スパン <スパン <スパン <スパン
im = Image.open("t.jpg").convert("1")
im
<イグ
正の範囲にオフセットする方法 は❓私は下記を使用しています。
data = ~np.array(im)
print("before removal:")
display(Image.fromarray(data))
ys, xs = np.where(data)
data = data[min(ys):max(ys)+1, min(xs):max(xs)+1]
print("After removal:")
display(Image.fromarray(data))
<イグ
上下両方の関数式がある場合のベタ恋の描き方も簡単です。
im = Image.fromarray(data).resize((60, 40), Image.ANTIALIAS)
data = np.array(im)
h, w = data.shape
print(f"Total {data.sum()} images needed, width {w}, height {h}")
Total of 1504 images, 60 wide and 40 high
<イグ
次に、軸を削除して画像を保存し、PILから直接読み込めるようにします。
ラブ画像を生成し、ファイルに保存する。
import os
def create_picture_wall(data, imgs, size=50):
h, w = data.shape
random_imgs = iter(np.random.choice(imgs, size=data.sum()))
new_img = Image.new('RGB', (size * w, size * h), "white")
for y, x in zip(*np.where(data)):
img_name = next(random_imgs)
src_img = Image.open(f'{img_path}/{img_name}')
src_img = src_img.resize((size, size), Image.ANTIALIAS)
# Copy the image to new_image
new_img.paste(src_img, (x * size, y * size))
return new_img
img_path = r"C:\Users\ASUS\Nox_share\ImageShare\avatar"
create_picture_wall(data, os.listdir(img_path))
画像を読み込んで白黒に変換すること。
import requests
from io import BytesIO
url = "https://staticc.ywordle.com/static/2020-11-01/6d2e4f9d31d1b7201e23198869de2f9a_preview.png"
r = requests.get(url)
im = Image.open(BytesIO(r.content))
im.size
(190, 200)
<イグ
ここで、余分な空白を取り除く必要があります。この白黒画像では、numpyを直接使って、境界線上の空白を取り除きました。
まずnumpyの配列に変換します。
data = np.array(im) > 0
data = np.array(Image.fromarray(data).resize((48, 50), Image.ANTIALIAS))
display(Image.fromarray(data))
<イグ
???? ラブフォトウォールを描こう ?
ラブマスクをつけると、簡単にフォトウォールを描くことができます。
最終的なレンダリングの量を減らすために、ハートの画像を少し拡大縮小します。
from PIL import Image
import requests
from io import BytesIO
import os
def get_mask_data(im, size=50):
width, height = im.size
if width > height:
height = height*size//width
width = size
else:
width = width*size//height
height = size
im = im.resize((width, height), Image.ANTIALIAS)
return np.array(im) > 0
def create_picture_wall(data, img_path, size=50):
h, w = data.shape
imgs = os.listdir(img_path)
random_imgs = iter(np.random.choice(imgs, size=data.sum()))
new_img = Image.new('RGB', (size * w, size * h), "white")
for y, x in zip(*np.where(data)):
img_name = next(random_imgs)
src_img = Image.open(f'{img_path}/{img_name}')
src_img = src_img.resize((size, size), Image.ANTIALIAS)
new_img.paste(src_img, (x * size, y * size))
return new_img
def download_img(url):
r = requests.get(url)
return Image.open(BytesIO(r.content))
url = "https://staticc.ywordle.com/static/2020-11-03/f18f814d52768eb29111c0be52b14ca2_preview.png"
im = download_img(url)
data = get_mask_data(im)
create_picture_wall(data, r"C:\Users\ASUS\Nox_share\ImageShare\avatar")
そして、描画を開始します。
import os
def create_picture_wall(data, imgs, size=50):
h, w = data.shape
random_imgs = iter(np.random.choice(imgs, size=data.sum()))
new_img = Image.new('RGB', (size * w, size * h), "white")
for y, x in zip(*np.where(data)):
img_name = next(random_imgs)
src_img = Image.open(f'{img_path}/{img_name}')
src_img = src_img.resize((size, size), Image.ANTIALIAS)
# Copy the image to new_image
new_img.paste(src_img, (x * size, y * size))
return new_img
img_path = r"C:\Users\ASUS\Nox_share\ImageShare\avatar"
create_picture_wall(data, os.listdir(img_path))
<イグ
もちろん、いくつかのシステム関連のキャッシュは画像のリストに追加され、その後、これらのシステムアイコンを手動で削除した後に生成することができます。
???? 任意のグラフィックフォトウォールを描く ?
ハートのフォトウォールを描く前に、実は自分でハートのグラフィックを描く必要はないんです。あらかじめグラフィックをマスクした画像を用意しておけば、それをPILで読み込んで、すぐに対応するフォトウォールに変換することができるのです。
マイクロワードクラウドのウェブサイトをご紹介します。 https://www.weiciyun.com/edit
様々なマスクシェイプは、以下のサイトでダウンロードできます。
サムズアップの例を使ってデモをしてみましょう。
import requests
from io import BytesIO
url = "https://staticc.ywordle.com/static/2020-11-01/6d2e4f9d31d1b7201e23198869de2f9a_preview.png"
r = requests.get(url)
im = Image.open(BytesIO(r.content))
im.size
(190, 200)
画像が大きすぎるため、bool配列に変換して少し拡大縮小してください:.
data = np.array(im) > 0
data = np.array(Image.fromarray(data).resize((48, 50), Image.ANTIALIAS))
display(Image.fromarray(data))
<イグ
でサムズアップフォトウォールを生成することができます。
上記のコードをラップするには
from PIL import Image
import requests
from io import BytesIO
import os
def get_mask_data(im, size=50):
width, height = im.size
if width > height:
height = height*size//width
width = size
else:
width = width*size//height
height = size
im = im.resize((width, height), Image.ANTIALIAS)
return np.array(im) > 0
def create_picture_wall(data, img_path, size=50):
h, w = data.shape
imgs = os.listdir(img_path)
random_imgs = iter(np.random.choice(imgs, size=data.sum()))
new_img = Image.new('RGB', (size * w, size * h), "white")
for y, x in zip(*np.where(data)):
img_name = next(random_imgs)
src_img = Image.open(f'{img_path}/{img_name}')
src_img = src_img.resize((size, size), Image.ANTIALIAS)
new_img.paste(src_img, (x * size, y * size))
return new_img
def download_img(url):
r = requests.get(url)
return Image.open(BytesIO(r.content))
これをテストするために
url = "https://staticc.ywordle.com/static/2020-11-03/f18f814d52768eb29111c0be52b14ca2_preview.png"
im = download_img(url)
data = get_mask_data(im)
create_picture_wall(data, r"C:\Users\ASUS\Nox_share\ImageShare\avatar")
<イグ
???? この記事を読んで、あなたはもうどんな種類のフォトウォールの描き方も知っていると思いますね? ☀️
関連
-
python draw bar chart error ValueError: shape mismatch: Objects cannot be broadcast to the single shape causes and solutions
-
[解決済み] argsortを降順で使用することは可能ですか?
-
[解決済み] _csv.Error: iterator should return strings, not bytes (did you open file in text mode?) [duplicate].
-
[解決済み] 文字列の先頭と末尾のゼロを削除するには?Python
-
[解決済み] Python matplotlib.dates.date2num: numpy の配列を matplotlib の datetimes に変換する
-
[解決済み] python numpy マシーンイプシロン
-
[解決済み] sklearn classifier get ValueError: Bad input shape.
-
UnsupportedOperation: 読み取れません。
-
ModuleNotFoundError: utils'という名前のモジュールがありません。
-
AttributeError: モジュール 'numpy' には属性 'dtype' がない 問題
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Travis CIでpython setup.pyがinvalid command 'bdist_wheel'と表示されるのはなぜですか?
-
[解決済み】npm - "Pythonの実行ファイル「python」が見つかりません。" env変数PYTHONを設定すればOKです。
-
Python環境設定時のVSコードの問題:'cmd'が内部コマンドまたは外部コマンドとして認識されない
-
Pythonの標準ライブラリPathlibはディレクトリとファイルを操作する
-
[解決済み] argparseによるブーリアン値のパース
-
[解決済み] import pandas_datareader gives ImportError: cannot import name 'is_list_like'
-
[解決済み] SQLAlchemy/Elixirでdistinctなカラム値を選択する
-
[解決済み] python エラー: pylab という名前のモジュールがありません。
-
[解決済み] リストからタプルを削除する方法
-
ModuleNotFoundError: mpl_toolkits.basemap'という名前のモジュールはありません。