text_plain_output_4.png text_plain_output_3.png image_output_4.png text_plain_output_2.png text_plain_output_1.png image_output_3.png image_output_2.png image_output_1.png
from PIL import Image

from matplotlib.colors import ListedColormap, LinearSegmentedColormap

from mpl_toolkits.axes_grid1 import make_axes_locatable

from skimage.feature import hog

from sklearn import preprocessing

from sklearn.metrics import confusion_matrix

from sklearn.model_selection import train_test_split

from torch.utils.data import Dataset

from torch.utils.data import Dataset

from torch.utils.data import SubsetRandomSampler, DataLoader

from torchvision import transforms, models

import cv2

import itertools

import matplotlib

import matplotlib.pyplot as plt

import numpy as np

import pandas as pd

import re

import seaborn as sns

import torch

import torch

import zipfile

import itertools
import zipfile
import re
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import cv2
from PIL import Image
from skimage.feature import hog
from sklearn import preprocessing
from sklearn import svm
from sklearn.cluster import KMeans
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
import torch
import torch.nn as nn
from torch.utils.data import Dataset
from torch.utils.data import SubsetRandomSampler, DataLoader
from torchvision import transforms, models
path = '../input/painter-by-numbers/'
df = pd.read_csv(path + 'all_data_info.csv')

file_path = '../input/painter-by-numbers/'
archive = zipfile.ZipFile(file_path + 'replacements_for_corrupted_files.zip', 'r')
corrupted_ids = set()
for item in archive.namelist():
    ID = re.sub('[^0-9]', '', item)
    if ID != '':
        corrupted_ids.add(ID)
drop_idx = []
for index, row in df.iterrows():
    id_check = re.sub('[^0-9]', '', row['new_filename'])
    if id_check in corrupted_ids:
        drop_idx.append(index)
df = df.drop(drop_idx)

painter_dict = {'Kandinsky': '', 'Dali': '', 'Picasso': '', 'Delacroix': '', 'Rembrandt': '', 'Gogh': '', 'Kuniyoshi': '', 'Dore': '', 'Steinlen': '', 'Saryan': '', 'Goya': '', 'Lautrec': '', 'Modigliani': '', 'Beksinski': '', 'Pissarro': '', 'Kirchner': '', 'Renoir': '', 'Piranesi': '', 'Degas': '', 'Chagall': ''}
paintings_dict = painter_dict.copy()
for artist in painter_dict:
    for painter in df['artist']:
        if artist in painter:
            painter_dict[artist] = painter
            paintings = df[df['artist'] == painter].shape[0]
            paintings_dict[artist] = paintings
            break
sample_size = min(paintings_dict.values())
min_a = list(paintings_dict.keys())[list(paintings_dict.values()).index(sample_size)]

active_df = pd.DataFrame({})
for artist in painter_dict.values():
    tr_df = df[df['artist'] == artist].sort_values(by=['in_train', 'size_bytes'], ascending=[False, True])
    active_df = pd.concat([active_df, tr_df.iloc[:sample_size]])

artists = list(painter_dict.values())
LabEnc = preprocessing.LabelEncoder()
LabEnc.fit(artists)

matplotlib.rc_file_defaults()
def image_transformer_nn(image, apply_norm=True, crop_img=True, new_dim=224):
    """
    Args:
        resize_num (int):
            Dimension (pixels) to resize image
        apply_norm (bool):
            Choose whether to apply the normalization or not
        crop_img (bool):
            Choose whether to resize the image into the new_dim size, or crop
            a square from its center, sized new_dim x new_dim
    """
    if crop_img:
        cropper = transforms.CenterCrop(new_dim)
        image = cropper(image)
    tensoring = transforms.ToTensor()
    image = tensoring(image)
    channels, height, width = image.shape
    if image.shape[0] < 3:
        image = image.expand(3, -1, -1)
    if image.shape[0] > 3:
        image = image[0:3, :, :]
    if apply_norm:
        normalizer = transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
        image = normalizer(image)
    if not crop_img:
        if width < height:
            image = image.transpose(1, 2)
        channels, height, width = image.shape
        res_percent = float(new_dim / width)
        height = round(height * res_percent)
        resizer = transforms.Resize((height, new_dim))
        image = resizer(image)
        padder = transforms.Pad([0, 0, 0, int(new_dim - height)])
        image = padder(image)
    return image
archive = zipfile.ZipFile(file_path + 'train.zip', 'r')
img_path = 'train/'
imgdata = archive.open(img_path + '69382.jpg')
image = Image.open(imgdata)
image2 = image_transformer_nn(image, apply_norm=False, crop_img=True, new_dim=224)
image3a = image_transformer_nn(image, apply_norm=False, crop_img=False, new_dim=224)
image3b = image_transformer_nn(image, apply_norm=True, crop_img=False, new_dim=224)

import torch
from torch.utils.data import Dataset
class ImageDataset(Dataset):
    def __init__(self, path, dataframe, lab_encoder, img_size=224, normalize=True, crop=False):
        """
        Args:
            path (string):
                Where to look for the files to extract
            dataframe (pd.DataFrame):
                dataframe to use for the IDs
            lab_encoder:
                label encoder to transform artist names into integers
            img_size (int):
                size to be used
            normalize (bool):
                perform normalization during transformation or not
            crop (bool):
                True: crop only a center from the image
                False: Resize image with respect to aspect ratio and pad
        """
        self.encoder = lab_encoder
        self.img_size = img_size
        self.normalize = normalize
        self.crop = crop
        self.feats, self.labels = self.get_all_items(path, dataframe)
    def get_all_items(self, path, dataframe):
        curr_df = dataframe[dataframe['in_train'] == True]
        archive = zipfile.ZipFile(path + 'train.zip', 'r')
        img_path = 'train/'
        feats = []
        labels = []
        for index, row in curr_df.iterrows():
            file = row['new_filename']
            imgdata = archive.open(img_path + file)
            try:
                image = Image.open(imgdata)
                datum = image_transformer_nn(image, apply_norm=self.normalize, crop_img=self.crop, new_dim=self.img_size)
                feats.append(datum)
                artist = row['artist']
                label = self.encoder.transform([artist])[0]
                labels.append(label)
            except Image.DecompressionBombError:
        curr_df = dataframe[dataframe['in_train'] == False]
        archive = zipfile.ZipFile(path + 'test.zip', 'r')
        img_path = 'test/'
        for index, row in curr_df.iterrows():
            file = row['new_filename']
            imgdata = archive.open(img_path + file)
            try:
                image = Image.open(imgdata)
                datum = image_transformer_nn(image, apply_norm=self.normalize, crop_img=self.crop, new_dim=self.img_size)
                feats.append(datum)
                artist = row['artist']
                label = self.encoder.transform([artist])[0]
                labels.append(label)
            except Image.DecompressionBombError:
        feats = torch.stack(feats)
        labels = torch.LongTensor(labels)
        return (feats, labels)
    def __len__(self):
        return len(self.labels)
    def __getitem__(self, item):
        return (self.feats[item], self.labels[item])

def ImageData(path, dataframe, lab_encoder, hog_mode, sift_mode, img_size=224):
    curr_df = dataframe[dataframe['in_train'] == True]
    archive = zipfile.ZipFile(path + 'train.zip', 'r')
    img_path = 'train/'
    PaintFeats = []
    PaintLabels = []
    for index, row in curr_df.iterrows():
        file = row['new_filename']
        imgdata = archive.open(img_path + file)
        try:
            image = Image.open(imgdata)
            datum = image_transformer_nn(image, apply_norm=False, crop_img=False, new_dim=img_size)
            np_datum = datum.numpy().transpose(1, 2, 0)
            if hog_mode:
                orients, ppc, cpb = (hog_mode[0], hog_mode[1], hog_mode[2])
                datum = hog(np_datum, orientations=orients, pixels_per_cell=ppc, cells_per_block=cpb, feature_vector=True, channel_axis=2)
                PaintFeats.append(datum)
            elif sift_mode:
                np_datum = cv2.normalize(np_datum, None, 0, 255, cv2.NORM_MINMAX).astype('uint8')
                imgtogray = cv2.cvtColor(np_datum, cv2.COLOR_BGR2GRAY)
                PaintFeats.append(imgtogray)
            artist = row['artist']
            label = lab_encoder.transform([artist])[0]
            PaintLabels.append(label)
        except Image.DecompressionBombError:
    curr_df = dataframe[dataframe['in_train'] == False]
    archive = zipfile.ZipFile(path + 'test.zip', 'r')
    img_path = 'test/'
    for index, row in curr_df.iterrows():
        file = row['new_filename']
        imgdata = archive.open(img_path + file)
        try:
            image = Image.open(imgdata)
            datum = image_transformer_nn(image, apply_norm=False, crop_img=False, new_dim=img_size)
            np_datum = datum.numpy().transpose(1, 2, 0)
            if hog_mode:
                orients, ppc, cpb = (hog_mode[0], hog_mode[1], hog_mode[2])
                datum = hog(np_datum, orientations=orients, pixels_per_cell=ppc, cells_per_block=cpb, feature_vector=True, channel_axis=2)
                PaintFeats.append(datum)
            elif sift_mode:
                np_datum = cv2.normalize(np_datum, None, 0, 255, cv2.NORM_MINMAX).astype('uint8')
                imgtogray = cv2.cvtColor(np_datum, cv2.COLOR_BGR2GRAY)
                PaintFeats.append(imgtogray)
            artist = row['artist']
            label = lab_encoder.transform([artist])[0]
            PaintLabels.append(label)
        except Image.DecompressionBombError:
    return (np.asarray(PaintFeats), np.asarray(PaintLabels))

def DataSplitter(data, ratios=[60, 20, 20], need_val=True, batches=None, shuffle=True, seed=None):
    """
    Args:
        data (Dataset or List):
            In the case of NN, it's the dataset to be loaded into loaders. In the case
            of other models, it's a list containing the Features and Labels lists
        batches (int):
            batch size for loaders in case of NN
        ratios (list):
            list of integers, containing the ratios [train,val,test] for splitting
            example: [60,25,15] means 60% train data, 25% val data and 15% test data
        shuffle (bool):
            option to shuffle data
        seed (None or int):
            seed for shuffling
    """
    first_ratio = (ratios[1] + ratios[2]) / sum(ratios)
    second_ratio = ratios[2] / (ratios[1] + ratios[2])
    if isinstance(data, ImageDataset):
        labels = data.labels.numpy()
        train_indices, rest_indices = train_test_split(np.arange(len(labels)), test_size=first_ratio, shuffle=shuffle, random_state=seed, stratify=labels)
        rest_labels = data[rest_indices][1]
        val_indices, test_indices = train_test_split(rest_indices, test_size=second_ratio, shuffle=shuffle, random_state=seed, stratify=rest_labels)
        train_sampler = SubsetRandomSampler(train_indices)
        val_sampler = SubsetRandomSampler(val_indices)
        test_sampler = SubsetRandomSampler(test_indices)
        train_loader = DataLoader(data, batch_size=batches, sampler=train_sampler)
        val_loader = DataLoader(data, batch_size=batches, sampler=val_sampler)
        test_loader = DataLoader(data, batch_size=batches, sampler=test_sampler)
        return (train_loader, val_loader, test_loader)
    elif isinstance(data, tuple):
        X_train, X_rest, y_train, y_rest = train_test_split(data[0], data[1], test_size=first_ratio, shuffle=shuffle, random_state=seed, stratify=data[1])
        if need_val:
            X_val, X_test, y_val, y_test = train_test_split(X_rest, y_rest, test_size=second_ratio, shuffle=shuffle, random_state=seed, stratify=y_rest)
            return (X_train, X_val, X_test, y_train, y_val, y_test)
        return (X_train, X_rest, y_train, y_rest)
    else:
        return

sns.set(style = "darkgrid") # Personal preference

def CustomCmap(from_rgb,to_rgb):

    # from color r,g,b
    r1,g1,b1 = from_rgb

    # to color r,g,b
    r2,g2,b2 = to_rgb

    cdict = {'red': ((0, r1, r1),
                   (1, r2, r2)),
           'green': ((0, g1, g1),
                    (1, g2, g2)),
           'blue': ((0, b1, b1),
                   (1, b2, b2))}

    cmap = LinearSegmentedColormap('custom_cmap', cdict)
    return cmap

mycmap = CustomCmap([1.0, 1.0, 1.0], [72/255, 99/255, 147/255])
mycmap_r = CustomCmap([72/255, 99/255, 147/255], [1.0, 1.0, 1.0])

mycol = (72/255, 99/255, 147/255)
mycomplcol = (129/255, 143/255, 163/255)

def plot_cm(cfmatrix,title,classes):
    fig, ax1 = plt.subplots(1,1) #, figsize=(5,5)

    for ax,cm in zip([ax1],[cfmatrix]):
        im = ax.imshow(cm, interpolation='nearest', cmap=mycmap)
        divider = make_axes_locatable(ax)
        cax = divider.append_axes("right", size="5%", pad=.2)
        plt.colorbar(im, cax=cax) #, ticks=[-1,-0.5,0,0.5,1]
        ax.set_title(title,fontsize=14)
        tick_marks = np.arange(len(classes))
        ax.set_xticks(tick_marks)
        ax.set_xticklabels(classes, rotation=90)
        ax.set_yticks(tick_marks)
        ax.set_yticklabels(classes)

        fmt = 'd'
        thresh = cm.max() / 2.

        for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
            ax.text(j, i, format(cm[i, j], fmt), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black")

        ax.set_ylabel('True label',fontsize=14)
        ax.set_xlabel('Predicted label',fontsize=14)

    plt.savefig(title+'.pdf', bbox_inches='tight')
    plt.show()

matplotlib.rc_file_defaults()
cfmatrix = confusion_matrix(y_true, y_pred)
plot_cm(cfmatrix, 'CNN Confusion Matrix', artists)