#=======================================================================
# Non-convolutional image filtering by bitmasks
#
# Cesare Brizio, 19 January 2023
#
# I did something similar around 15 years ago in Visual Basic,
# with the heavy burden of a Visual Studio installation.
# Thanks to Python, I can provide a working example with in a
# much lighter environment.
#
# The main purpose here is to illustrate the application of 
# bitmasks and bitwise operations such as bitwise AND
# to RGB 24-bit images.
#
# "cat image" 1.jpg is available as a part of the
#  Cats vs. Dogs dataset from Kaggle 
# (https://www.kaggle.com/datasets/pybear/cats-vs-dogs?select=PetImages)
#=======================================================================

import numpy as np
from PIL import Image, ImageOps
from matplotlib import pyplot as plt
from matplotlib import image as mpimg
from matplotlib import colors as mcolors
from numpy import asarray
import cv2

def plot_image(img: np.array):
    plt.figure(figsize=(6, 6), dpi=96)
    plt.title("Cat Image")
    plt.xlabel("X pixel scaling")
    plt.ylabel("Y pixels scaling")
    #plt.imshow(img, cmap='gray');
    plt.imshow(img);
    plt.show()
    
def plot_two_images(img1: np.array, img2: np.array, imm_name):
    _, ax = plt.subplots(1, 2, figsize=(12, 6), dpi=96)
    plt.title(imm_name)
    plt.xlabel("X pixel scaling")
    plt.ylabel("Y pixels scaling")    
    #ax[0].imshow(img1, cmap='gray')
    #ax[1].imshow(img2, cmap='gray');    
    ax[0].imshow(img1)
    ax[1].imshow(img2);
    plt.show()

Mask_Top_Pass  = 0xC0C0C0 #bitwise AND preserves the two "high" bits
Mask_High_Pass = 0xE0E0E0 #bitwise AND preserves the three "high" bits
Mask_Mid_Pass  = 0X7E7E7E #bitwise AND preserves the six "middle" bits
Mask_Core_Pass  = 0X3C3C3C #bitwise AND preserves the four "middle" bits
Mask_Low_Pass  = 0X070707 #bitwise AND preserves the three "low" bits
Mask_Bot_Pass  = 0X030303 #bitwise AND preserves the two "low" bits

def BITMASK_HP(img: np.array, curr_mask:float) -> np.array:

    # A copy of the image - will be overwritten
    bitmasked_img = img.copy()
    
    h, w, c = img.shape

    #----------------------------------------------------
    # BEGIN nested loops to apply the bit mask
    #----------------------------------------------------
    # Iterate over the rows
    for i in range(h):
        # Iterate over the columns
        for j in range(w):
            # img[i, j] = individual pixel value
            # Get the current pixel
            pix = img[i, j]
            # Apply the bit mask
            # Store the result to i-th row and j-th column of our convolved_img array
            bitmasked_img[i, j] = pix & curr_mask
    #----------------------------------------------------
    # END nested loops to apply the bit mask
    #----------------------------------------------------            
    
    return bitmasked_img




#=======================================================
# LOAD THE ORIGINAL IMAGE by CV2.IMREAD method
#=======================================================
img_BGR = cv2.imread('C:/Conv_Python/images/1.jpg')

img = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB)

plot_image(img=img)  

image_to_save = Image.fromarray(img,'RGB')
image_to_save.save("original_image.jpg")


#===================================
#  Bitmask Top Pass
#  0xC0C0C0 #bitwise AND preserves the two "high" bits
#===================================
Curr_Title="Cat Image - BITMASK TOP PASS"
img_bmask_tp = BITMASK_HP(img=np.array(img), curr_mask=Mask_Top_Pass)
img_bmask_tp   

plot_two_images(
    img1=img, 
    img2=img_bmask_tp,
    imm_name=Curr_Title
)     

image_to_save = Image.fromarray(img_bmask_tp,'RGB')
image_to_save.save("bitmasked_tp_img.jpg")


#===================================
#  Bitmask High Pass
#  0xE0E0E0 #bitwise AND preserves the three "high" bits
#===================================
Curr_Title="Cat Image - BITMASK HIGH PASS"
img_bmask_hp = BITMASK_HP(img=np.array(img), curr_mask=Mask_High_Pass)
img_bmask_hp   

plot_two_images(
    img1=img, 
    img2=img_bmask_hp,
    imm_name=Curr_Title
)     

image_to_save = Image.fromarray(img_bmask_hp,'RGB')
image_to_save.save("bitmasked_hp_img.jpg")


#===================================
#  Bitmask Mid Pass
#  0X7E7E7E #bitwise AND preserves the six "middle" bits
#===================================
Curr_Title="Cat Image - BITMASK MID PASS"
img_bmask_mp = BITMASK_HP(img=np.array(img), curr_mask=Mask_Mid_Pass)
img_bmask_mp   

plot_two_images(
    img1=img, 
    img2=img_bmask_mp,
    imm_name=Curr_Title
)     

image_to_save = Image.fromarray(img_bmask_mp,'RGB')
image_to_save.save("bitmasked_mp_img.jpg")


#===================================
#  Bitmask Core Pass
#  0X3C3C3C #bitwise AND preserves the four "middle" bits
#===================================
Curr_Title="Cat Image - BITMASK CORE PASS"
img_bmask_cp = BITMASK_HP(img=np.array(img), curr_mask=Mask_Core_Pass)
img_bmask_cp   

plot_two_images(
    img1=img, 
    img2=img_bmask_cp,
    imm_name=Curr_Title
)     

image_to_save = Image.fromarray(img_bmask_cp,'RGB')
image_to_save.save("bitmasked_cp_img.jpg")


#===================================
#  Bitmask Low Pass
#  0X070707 #bitwise AND preserves the three "low" bits
#===================================
Curr_Title="Cat Image - BITMASK LOW PASS"
img_bmask_lp = BITMASK_HP(img=np.array(img), curr_mask=Mask_Low_Pass)
img_bmask_lp   

plot_two_images(
    img1=img, 
    img2=img_bmask_lp,
    imm_name=Curr_Title
)     

image_to_save = Image.fromarray(img_bmask_lp,'RGB')
image_to_save.save("bitmasked_lp_img.jpg")


#===================================
#  Bitmask Bottom Pass
#  0X030303 #bitwise AND preserves the two "low" bits
#===================================
Curr_Title="Cat Image - BITMASK BOTTOM PASS"
img_bmask_bp = BITMASK_HP(img=np.array(img), curr_mask=Mask_Bot_Pass)
img_bmask_bp   

plot_two_images(
    img1=img, 
    img2=img_bmask_bp,
    imm_name=Curr_Title
)     

image_to_save = Image.fromarray(img_bmask_bp,'RGB')
image_to_save.save("bitmasked_bp_img.jpg")