"""
#### Convolutional Neural Network Dogs and Cats -keras

##### Before understanding the CNN, lets understand first about these two core subject
![image.png](attachment:image.png)
**Image processing** is a method to perform some operations on an image, in order to get an enhanced image or to extract some useful information from it. It is a type of signal processing in which input is an image and output may be image or characteristics/features associated with that image.

**Computer vision** is a field of computer science that works on enabling computers to see, identify and process images in the same way that human vision does, and then provide appropriate output. It is like imparting human intelligence and instincts to a computer. In reality though, it is a difficult task to enable computers to recognize images of different objects.

### Content:
#### Explanation
* Convolution operation
* ReLU
* Max Pooling
* Flattening
* Full-connection Softmax & Cross entropy

#### IMPLEMENTATION
* Data preprocessing
* Build the Keras model
* Compile and fit the model
* Make predictions and determine accuracy
"""
import matplotlib.pyplot as plt
import matplotlib.image as mpimage
import numpy as np
import cv2
import os
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Conv2D, MaxPool2D, Flatten, Dense

from sklearn.metrics import confusion_matrix
TRAIN_DIR='../input/cat-and-dog/training_set/training_set/'
TEST_DIR='../input/cat-and-dog/test_set/test_set/'


train_cat_dir=TRAIN_DIR+'cats'
train_dog_dir=TEST_DIR+'dogs'

train_cat_fnames=os.listdir(train_cat_dir)
train_dog_fnames=os.listdir(train_dog_dir)

# test_cat_fnames=os.listdir(test_dir+'cats')
# test_dog_fnames=os.listdir(test_dir+'dogs')
num_rows=4
num_cols=4
pic_index=0
fig=plt.gcf()
fig.set_size_inches(num_rows*4,num_cols*4)

pic_index+=8

next_cat_pix=[os.path.join(train_cat_dir,fname) for fname in train_cat_fnames[pic_index-8:pic_index]]
next_dog_pix=[os.path.join(train_dog_dir,fname) for fname in train_dog_fnames[pic_index-8:pic_index]]

for i,img_path in enumerate(next_cat_pix+next_dog_pix):
    sp=plt.subplot(num_rows,num_cols,i+1)
    sp.axis('off')
    
    img=mpimage.imread(img_path)
    plt.imshow(img)
"""
### Model Building in CNN
"""
# Initialising the CNN
cnn_model = Sequential();
# step 1 convolution layer
# 64,64 means number of the channel in row and columns.
# 32 is the number of detactores, 3X3 cross matrix(filter size) we can also increas depend on gpu/cpu
cnn_model.add(Conv2D(32, (3, 3), input_shape=(64,64,3), activation='relu')) 
# step 2 Pooling
cnn_model.add(MaxPool2D(pool_size=(2,2)))
# Adding a second convolutional layer
cnn_model.add(Conv2D(64, (3, 3), activation='relu'))
# step 2 Pooling
cnn_model.add(MaxPool2D(pool_size=(2,2)))
cnn_model.add(Conv2D(128, (3, 3), activation='relu'))
cnn_model.add(MaxPool2D(pool_size=(2,2)))
cnn_model.add(Conv2D(128,(3,3),activation='relu'))
cnn_model.add(MaxPool2D(pool_size=(2,2)))

# step 3 Flattening creating a long vector
cnn_model.add(Flatten())
# step 4 Full connection
cnn_model.add(Dense(units=512, activation='relu'))
cnn_model.add(Dense(units=1, activation='sigmoid'))
# Compleate CNN
cnn_model.compile(optimizer='adam',loss="binary_crossentropy", metrics=['accuracy'])
"""
Note that when we have only two classes, we could instead configure our output layer to have only one output, rather than two, and use **binary_crossentropy** as our loss, rather than ***categorical_crossentropy***. Both options work equally well and achieve the exact same result.

With ***binary_crossentropy***, however, the last layer would need to use ***sigmoid***, rather than ***softmax***, as its activation function.
"""
#Data augmentation

train_datagen = ImageDataGenerator(rescale=1./255, #Rescaling factor
                                   shear_range=0.2, # float shear intensity 
                                   zoom_range=0.2, #Range for random zoom float(lower/upper)
                                   horizontal_flip=True) # Random flip inputs horizontally
test_datagen = ImageDataGenerator(rescale=1./255)
training_set = train_datagen.flow_from_directory(TRAIN_DIR,
                                                 target_size=(64, 64),
                                                 batch_size=32,
                                                 class_mode='binary')
test_set = test_datagen.flow_from_directory(TEST_DIR,
                                            target_size=(64, 64),
                                            batch_size=32,
                                            class_mode='binary')
history=cnn_model.fit(training_set,
              steps_per_epoch=200,
              epochs=25,
              validation_data=test_set,
              validation_steps=50)
# plot accuracy and loss


acc = history.history["accuracy"]
val_acc = history.history["val_accuracy"]
loss = history.history["loss"]
val_loss = history.history["val_loss"]

epochs = range(1, len(acc) + 1)

# accuracy

plt.plot(epochs, acc, "b", label="Training accuracy")
plt.plot(epochs, val_acc, "b--", label="Validation accuracy")
plt.title("Training and validation accuracy")
plt.legend()
plt.show()

# loss

plt.plot(epochs, loss, "r", label="Training loss")
plt.plot(epochs, val_loss, "r--", label="Validation loss")
plt.title("Training and validation loss")
plt.legend()
plt.show()
# Predictions for Dog image using train model

# from keras.preprocessing import image
# test_image = image.load_img('/content/training_set/training_set/cats/cat.1.jpg',target_size=(64,64))
# test_image = image.img_to_array(test_image)
# test_image = np.expand_dims(test_image, axis=0)


test_image = cv2.imread("/kaggle/input/cat-and-dog/training_set/training_set/cats/cat.1903.jpg")
plt.imshow(test_image)

test_image = cv2.resize(test_image,None, fx = 0.5, fy=0.5)
test_image = test_image.reshape()

result = cnn_model.predict(test_image)
training_set.class_indices
if result[0][0]==1:
  prediction = 'dog'
  print(prediction)
else:
  prediction = 'cat'
  print(prediction)
# Predictions for Dog image using train model
test_image = cv2.imread("/kaggle/input/cat-and-dog/training_set/training_set/dogs/dog.1903.jpg")
plt.imshow(test_image)

test_image = cv2.resize(test_image,None, fx = 0.5, fy=0.5)
test_image = test_image.reshape()

result = cnn_model.predict(test_image)
training_set.class_indices
if result[0][0]==1:
  prediction = 'dog'
  print(prediction)
else:
  prediction = 'cat'
  print(prediction)
"""
##### Now that we have a general understanding for how to build and work with a CNN using Keras
"""