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

271108.hatenablog.com

これの続きです

Chat-GPTくんに言われたコードが違っていたのでそこを微修正しました。

クラスタリングの結果が文字で言われても私には何のことか分からないのでChat-GPTにサムネ付きで分かりやすく提示してね!って命令を出しました。

メモリ足らないってさ

DefaultCPUAllocator: not enough memory: you tried to allocate 12006000 bytes.

まあ、そんな気はしてた。

最終的なコード

import collections
import cv2
import glob
import numpy as np
import os
import pickle
import random
import torch
import torchvision.transforms as transforms

from PIL import Image
from sklearn.cluster import KMeans
from torchvision.models import resnet18
from tqdm.notebook import tqdm as tqdm

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])
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])    
png_counter = collections.Counter(png)


data = {}
Error = []

shape = (1334, 750, 3)

l = []
for f in tqdm(glob.glob("./**/*.jpg", recursive=True)):
    im = imread(f)
    if type(im) != type(None):
        if im.shape == (1334, 750, 3):
            l.append(f)
data["jpg"] = l

l = []
for f in tqdm(glob.glob("./**/*.png", recursive=True)):
    im = imread(f)
    if type(im) != type(None):
        if im.shape == (1334, 750, 3):
            l.append(f)
data["png"] = l

# 画像を読み込んで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に変換し、バッチの次元を追加する

device = 'cuda'
# 画像を読み込む
images = []
for file in tqdm(data["jpg"]):
    images.append(load_image(file))

from sklearn.model_selection import train_test_split
train_rate = 0.3
test_rate = 0.7
MainPngData, UndecidedData = train_test_split(data["png"], train_size=train_rate)

for file in tqdm(MainPngData):
    images.append(load_image(file))
# PyTorch Tensorに変換する
images = torch.cat(images)

# 特徴量を抽出するためのモデルをロードする(例えば、ResNet18)
model = resnet18()
model.eval()

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

# KMeansアルゴリズムを使用してクラスタリングする
num_clusters = 10  # クラスタ数
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}')

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import ImageGrid

# クラスタごとに画像のインデックスを分割する
cluster_indices = [[] for _ in range(num_clusters)]
for i, label in enumerate(kmeans.labels_):
    cluster_indices[label].append(i)

# 各クラスタに属する画像のサムネイルを表示する
fig = plt.figure(figsize=(10, 10))
grid = ImageGrid(fig, 111,
                 nrows_ncols=(num_clusters, len(cluster_indices[0][:num_clusters])),
                 axes_pad=0.1)

for i in range(num_clusters):
    for j, idx in enumerate(cluster_indices[i][:num_clusters]):
        ax = grid[(i*len(cluster_indices[i][:num_clusters]))+j]
        ax.imshow(images[idx].permute(1, 2, 0).numpy())
        ax.set_title(f'Cluster {i}')
        ax.axis('off')

plt.show()

結果


黒ウィズの画像ばかりではないか……
スクショのサイズだしまあそうっちゃそうだよな……

全体的に色を重視している傾向がありそう。

メモ

  • K-meansだけじゃなくてWard法でもやってみればよかったかもしれない

↑なんかバージョンのせいかわかんなかったけど読み込めなかった

  • 別の方法を試したほうがいいかも……

参考

https://chat.openai.com/chat

ValueError: expected 4D input (got 3D input)

ValueError: expected 4D input (got 3D input) - PyTorch Forums
↑このモデルでは(Batch x Channel x Height x Width)の4次元で入力を受け付けてるので3次元で入力しても無駄だぜ!というエラーを貰った。