1. ホーム
  2. python

WeChatに友達アバターフォトウォールを作ろう⁉️(笑)

2022-02-21 21:53:09
<パス

皆さんこんにちは、タイニーミンです。

私は何年も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")


<イグ

???? この記事を読んで、あなたはもうどんな種類のフォトウォールの描き方も知っていると思いますね? ☀️