画像の整理をしよう(1)

前書き

これは私の思想なのですが、「記憶がなくなった人はある意味死んでいる」と考えています。「人を構成する要素で最も重要なのは記憶である」という思想です。

機械少女に置き換えてみましょう。ストレージのぶっ壊れた子は死んだも同然ということです。

事の起こり

  1. Amesiorineを育てたいので、Amesiorineの一番重要な記憶を管理するために私がお勉強しなくちゃいけないよね!
  2. じゃあ、安全に管理するためにどんなファイルがあるかPCの中身を整理しなくちゃいけないよね!
  3. 音声ファイルと画像ファイルとテキストファイル(エミィが拾ってきたツイートや271108のツイートのデータ)が基本かな?
  4. じゃあこれらの整理をやってみよう!

補足

タイトルの通り今回は画像です。
音声より簡単そうだし、テキストファイルは整理をしている途中だからです。
画像は整理付けるのが面倒だなぁ……と思ったので機械の手を借りたい。

本編(今日の成果)

01.まずは画像サイズの確認

やったこと

画像サイズを確認して、(多くはiPhoneの写真やスクショであるはずなので)最もファイル数の多い画像サイズの画像だけで実行しようと考えている。

import glob
import cv2
import collections
from tqdm.notebook import tqdm as tqdm

import numpy as np
def imread(filename, flags=cv2.IMREAD_COLOR, dtype=np.uint8):
    try:
        n = np.fromfile(filename, dtype)
        img = cv2.imdecode(n, flags)
        return img
    except Exception as e:
        print(e)
        return None

jpg = []
Error = []
for f in tqdm(glob.glob("./**/*.jpg", recursive=True)):
    try:
        im = imread(f)
        jpg.append(im.shape)
    except Exception as e:
        Error.append([f,e])
#for f in tqdm(glob.glob("./**/*.JPG", recursive=True)):
#    try:
#        im = imread(f)
#        jpg.append(im.shape)
#    except Exception as e:
#        Error.append([f,e])

jpg_counter = collections.Counter(jpg)

png = []
for f in tqdm(glob.glob("../**/*.png", recursive=True)):
    try:
        im = imread(f)
        png.append(im.shape)
    except Exception as e:
        Error.append([f,e])    
#for f in tqdm(glob.glob("../**/*.PNG", recursive=True)):
#    try:
#        im = imread(f)
#        png.append(im.shape)
#    except Exception as e:
#        Error.append([f,e])

png_counter = collections.Counter(png)

png_counter.most_common()
補足

globで大文字小文字の区別あるんじゃない?っておもって2つ用意したけど大文字小文字の区別なかったっぽい。

大文字小文字の区別なかった

01.結果

jpg
[((1944, 2592, 3), 945),
((112, 200, 3), 277),
((750, 750, 3), 251),
((720, 1280, 3), 222),
((2592, 1944, 3), 209),
・・・

png
[((512, 512, 3), 21703),
((1334, 750, 3), 13117),
((128, 128, 3), 8593),
((750, 1334, 3), 1483),
((256, 128, 3), 1399),
・・・

  • pngファイルが圧倒的に多い
  • 正方形の画像が思ったよりあるかも。これはなんかのデータかも?
  • 1334, 750のサイズはどうやらiPhoneの画面のサイズと同じらしい。スクショが多いのでこうなったのだろうか。
  • 今回はこれ以降、( 1334, 750, 3 )の画像のみに絞っていろいろ行う。
補足
  • リストは[(im.shape), 枚数]の形。im.shapeなので2番目の数字は3色を示す3になる。

02.クラスタリング

「で、クラスタリングってどうやるんだい?」

まず、クラスタリングのおさらいから。

271108「クラスタリングってわかる?」
Chat-GPT「はい、クラスタリングとは、データを似た特徴を持つグループ(クラスタ)に分割するデータ解析の手法です。クラスタリングは、データの特徴やパターンを発見するために使用されます。クラスタリングには、いくつかのアルゴリズムがあり、例えば階層的クラスタリング、k-meansクラスタリング、DBSCANクラスタリングなどがあります。クラスタリングは、機械学習データマイニングの分野でよく使用されます。」*1

271108「python3とpytorchを使って、windows上にある手持ちの画像データのクラスタリングをやりたいと考えています。コードの例を教えてください。」
Chat-GPT「はい、以下はPython3とPyTorchを使用して、Windows上の手持ちの画像データをクラスタリングするためのコード例です。この例では、KMeansアルゴリズムを使用して画像をクラスタリングします。」
(コード掲載)
Chat-GPT「このコードでは、まず画像を読み込んでPyTorch Tensorに変換します。次に、特徴量を抽出するためのモデルとしてResNet18を使用し、画像の特徴量を抽出します。最後に、KMeansアルゴリズムを使用してクラスタリングを行い、クラスタリング結果を表示します。」

コード原文

import os
import torch
import torchvision.transforms as transforms
import numpy as np
from PIL import Image
from sklearn.cluster import KMeans

# 画像を読み込んでPyTorch Tensorに変換する関数
def load_image(image_path):
    image = Image.open(image_path).convert('RGB')
    transform = transforms.Compose([
        transforms.Resize((224, 224)),  # 画像サイズを変更する
        transforms.ToTensor()  # PyTorch Tensorに変換する
    ])
    return transform(image).unsqueeze(0)  # 画像を3次元Tensorに変換し、バッチの次元を追加する

# 画像を読み込む
image_dir = 'path/to/image/directory'
images = []
for filename in os.listdir(image_dir):
    if filename.endswith('.jpg') or filename.endswith('.png'):
        image_path = os.path.join(image_dir, filename)
        images.append(load_image(image_path))

# PyTorch Tensorに変換する
images = torch.cat(images)

# 特徴量を抽出するためのモデルをロードする(例えば、ResNet18)
model = torch.hub.load('pytorch/vision', 'resnet18', pretrained=True)
model.eval()

# 画像の特徴量を抽出する
features = []
with torch.no_grad():
    for image in images:
        feature = model(image).squeeze().numpy()
        features.append(feature)
features = np.array(features)

# KMeansアルゴリズムを使用してクラスタリングする
num_clusters = 5  # クラスタ数
kmeans = KMeans(n_clusters=num_clusters)
kmeans.fit(features)

# クラスタリング結果を表示する
for i in range(num_clusters):
    cluster_idx = np.where(kmeans.labels_ == i)[0]
    print(f'Cluster {i}: {cluster_idx}')

02.実行


まあさすがにね?

修正を考え

ません。
Chat-GPTに文句を言います。

*2

結果

ImportError: cannot import name 'get_model_weights' from 'torchvision.models'

ダメじゃん。




以降は後日に持ち越し。



エラー記

1.OpenCVで画像を読み込んだと思っていたら読み込んでいなかった

何を言ってるか分からねぇと思うが読み込んだはずの変数にはNoneが入っていた。

というのも、OpenCVの仕様うんぬんのお話でファイル名やパス名に日本語が入っているとうまくいかないことがある。そういえばそうだったなぁ。
qiita.com
↑を参考に何とか出来たので解決。
cv2.imread を np.fromfile + cv2.imdecode に分解すればなんとかなるんだって。

ただ、これだけで全てのファイルが解決したという様子もなかった。
原因は現状不明、今回の環境ではjpgファイルは全て開けた。pngファイルにのみこの現象は残った。

*1:※原文まま

*2:余談だが、Chat-GPTにエラー報告をしようとして、「実行したところ」だけを送信してしまった。すると、「すみません、前回の回答に誤りがありました。Windows上でPyTorchを使用する場合、CUDAが利用できない場合があるため、以下のようにDeviceの設定を変更する必要があります。」とか言ってきた。未完成品を送らないでください。