Template Matching using OpenCV Python

image_gray: np.ndarray
TM_METHOD=cv2.TM_CCOEFF_NORMED

def __init__(self):
    self.take_screenshot()

def take_screenshot(self):
    user32 = ctypes.windll.user32
    user32.SetProcessDPIAware()
    image = ImageGrab.grab()
    # save on file
    # image.save('screenshot.jpg', format='JPEG', quality=20)

    # load image from memory
    image_rgb = np.array(image)

    # load from file
    # image_rgb=cv2.imread('screenshot.jpg')
    self.image_gray = cv2.cvtColor(image_rgb, cv2.COLOR_BGR2GRAY)

@staticmethod
def save_screenshot():
    user32 = ctypes.windll.user32
    user32.SetProcessDPIAware()
    image = ImageGrab.grab()
    image.save("screenshot.jpg")

def template_available(self, template_path: str, threshold=0.9):

    # self.take_screenshot()

    template = cv2.imread(template_path, 0)
    # w, h = template.shape[::-1]

    res = cv2.matchTemplate(self.image_gray, template, self.TM_METHOD)
    loc = np.where(res >= threshold)

    if len(loc[0]) == 0 & len(loc[1]) == 0:
        return False
    else:
        print("template_available : " + template_path)
        return True

def template_count(self, template_path: str, threshold=0.9):

    # self.take_screenshot()

    template = cv2.imread(template_path, 0)
    # w, h = template.shape[::-1]

    res = cv2.matchTemplate(self.image_gray, template, self.TM_METHOD)
    loc = np.where(res >= threshold)

    return len(loc[0])

def template_location(self, template_path: str, threshold=0.9):

    self.take_screenshot()

    template = cv2.imread(template_path, 0)
    w, h = template.shape[::-1]

    res = cv2.matchTemplate(self.image_gray, template, self.TM_METHOD)
    loc = np.where(res >= threshold)

    if len(loc[0]) == 0 & len(loc[1]) == 0:
        return None
    else:
        click_y = loc[0][0] + h / 2
        click_x = loc[1][0] + w / 2

        return click_x, click_y

def move_mouse_to_template(self, template_path: str):
    loc = self.template_location(template_path)

    if loc is not None:
        click_x = loc[0]
        click_y = loc[1]
        pyautogui.moveTo(click_x, click_y)

def click_template(self, template_path: str, threshold=0.9):
    loc = self.template_location(template_path, threshold)

    if loc is not None:
        click_x = loc[0]
        click_y = loc[1]
        pyautogui.click(click_x, click_y)
        pyautogui.FAILSAFE = False
        pyautogui.moveTo(0, 0)
        print("click_template : " + template_path)
        return True

    return False

@staticmethod
def scroll_mouse(value=10):
    pyautogui.scroll(value)
    pyautogui.FAILSAFE = False
    pyautogui.moveTo(0, 0)

@staticmethod
def get_template_path(template: str):
    template_name = f"template{template}.jpg"
    template_path = os.path.join(os.getcwd(), 'templates', template_name)
    return template_path

 

Take Screenshot using Python PIL

# Importing Image and ImageGrab module from PIL package 
from PIL import Image, ImageGrab 
  
# creating an image object 
im1 = Image.open(r"C:\Users\sadow984\Desktop\download2.JPG") 
  
# using the grab method 
im2 = ImageGrab.grab(bbox = None) 
  
im2.show() 

Taking screenshots of specific size or taking screenshots from specific region

# Importing Image and ImageGrab module from PIL package 
from PIL import Image, ImageGrab 
  
# creating an image object 
im1 = Image.open(r"C:\Users\sadow984\Desktop\download2.JPG") 
  
# using the grab method 
im2 = ImageGrab.grab(bbox =(0, 0, 300, 300)) 
  
im2.show() 

Parameters: box – The crop rectangle, as a (left, upper, right, lower)-tuple.

References
https://www.geeksforgeeks.org/pyhton-pil-imagegrab-grab-method/
https://stackoverflow.com/questions/19697210/taking-screen-shots-of-specific-size
https://stackoverflow.com/questions/47337811/what-do-the-parameters-of-bbox-mean-in-pillow

numpy.where() in Python

returns the indices of elements in an input array where the given condition is satisfied.

# Python program explaining 
# where() function 

import numpy as np 

np.where([[True, False], [True, True]], 
    [[1, 2], [3, 4]], [[5, 6], [7, 8]]) 
# Python program explaining 
# where() function 

import numpy as np 

# a is an array of integers. 
a = np.array([[1, 2, 3], [4, 5, 6]]) 

print(a) 

print ('Indices of elements <4') 

b = np.where(a<4) 
print(b) 

print("Elements which are <4") 
print(a[b]) 

References
https://www.geeksforgeeks.org/numpy-where-in-python/

Querying data with Pandas .query() method

Single condition filtering

# importing pandas package 
import pandas as pd 

# making data frame from csv file 
data = pd.read_csv("employees.csv") 

# replacing blank spaces with '_' 
data.columns =[column.replace(" ", "_") for column in data.columns] 

# filtering with query method 
data.query('Senior_Management == True', inplace = True) 

# display 
data 

Multiple condition filtering

# importing pandas package 
import pandas as pd 

# making data frame from csv file 
data = pd.read_csv("employees.csv") 

# replacing blank spaces with '_' 
data.columns =[column.replace(" ", "_") for column in data.columns] 

# filtering with query method 
data.query('Senior_Management == True
      and Gender =="Male" and Team =="Marketing"
      and First_Name =="Johnny"', inplace = True) 

# display 
data 

References
https://www.geeksforgeeks.org/python-filtering-data-with-pandas-query-method/

Get unique values from a column in Pandas DataFrame

len(gapminder['country'].unique().tolist())
set(df['region'].values.tolist())
# Create a list of unique values by turning the
# pandas column into a set
list(set(df.trucks))
# Create a list of unique values in df.trucks
list(df['trucks'].unique())
# Import pandas package 
import pandas as pd 

# create a dictionary with five fields each 
data = { 
  'A':['A1', 'A2', 'A3', 'A4', 'A5'], 
  'B':['B1', 'B2', 'B3', 'B4', 'B4'], 
  'C':['C1', 'C2', 'C3', 'C3', 'C3'], 
  'D':['D1', 'D2', 'D2', 'D2', 'D2'], 
  'E':['E1', 'E1', 'E1', 'E1', 'E1'] } 

# Convert the dictionary into DataFrame 
df = pd.DataFrame(data) 

# Get the unique values of 'B' column 
df.B.unique() 
# Import pandas package 
import pandas as pd 

# create a dictionary with five fields each 
data = { 
  'A':['A1', 'A2', 'A3', 'A4', 'A5'], 
  'B':['B1', 'B2', 'B3', 'B4', 'B4'], 
  'C':['C1', 'C2', 'C3', 'C3', 'C3'], 
  'D':['D1', 'D2', 'D2', 'D2', 'D2'], 
  'E':['E1', 'E1', 'E1', 'E1', 'E1'] } 

# Convert the dictionary into DataFrame 
df = pd.DataFrame(data) 

# Get number of unique values in column 'C' 
df.C.nunique(dropna = True) 

References
https://pythonprogramming.net/graph-visualization-python3-pandas-data-analysis/
https://www.geeksforgeeks.org/get-unique-values-from-a-column-in-pandas-dataframe/
https://chrisalbon.com/python/data_wrangling/pandas_find_unique_values/
https://cmdlinetips.com/2018/01/how-to-get-unique-values-from-a-column-in-pandas-data-frame/

Sort rows or columns in Dataframe based on values in Pandas

DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')

Sort Dataframe rows based on a single column

# Sort the rows of dataframe by column 'Name'
dfObj = dfObj.sort_values(by ='Name' )
print("Contents of Sorted Dataframe based on a single column 'Name' : ")
print(dfObj)

Sort Dataframe rows based on a multiple columns

dfObj = dfObj.sort_values(by =['Name', 'Marks'])
print("Contents of a Sorted Dataframe based on multiple columns 'Name' & 'Marks' : ")
print(dfObj)

Sort Dataframe rows based on columns in Descending Order

# Sort the rows of dataframe by column 'Name' in descending order
dfObj = dfObj.sort_values(by ='Name' , ascending=False)
print("Contents of Sorted Dataframe based on a column 'Name' in Descending Order : ")
print(dfObj)

Sort Dataframe rows based on a column in Place

# Sort the rows of dataframe by column 'Name' inplace
dfObj.sort_values(by='Name' , inplace=True)
print("Contents of Sorted Dataframe based on a single column 'Name' inplace: ")
print(dfObj)

Sort columns of a Dataframe based on a single row

dfObj = dfObj.sort_values(by ='b', axis=1)
print("Contents of Sorted Dataframe based on a single row index label 'b' ")
print(dfObj)

Sort columns of a Dataframe in Descending Order based on a single row

dfObj = dfObj.sort_values(by ='b', axis=1)
print("Contents of Sorted Dataframe based on a single row index label 'b' ")
print(dfObj)

Sort columns of a Dataframe based on a multiple rows

dfObj = dfObj.sort_values(by ='b', axis=1)
print("Contents of Sorted Dataframe based on a single row index label 'b' ")
print(dfObj)

Complete example is as follows:

import pandas as pd
def main():
# List of Tuples
students = [ ('Jack', 34, 'Sydney') ,
('Riti', 41, 'Delhi' ) ,
('Aadi', 16, 'New York') ,
('Riti', 22, 'Delhi' ) ,
('Riti', 35, 'Delhi' ) ,
('Riti', 40, 'Mumbai' )
]
# Create a DataFrame object
dfObj = pd.DataFrame(students, columns=['Name', 'Marks', 'City'], index=['b', 'a', 'f', 'e', 'd', 'c'])
print("Original Dataframe : ")
print(dfObj)
print('**** Sort Dataframe rows based on a single column ****')
# Sort the rows of dataframe by column 'Name'
dfObj = dfObj.sort_values(by ='Name' )
print("Contents of Sorted Dataframe based on a single column 'Name' : ")
print(dfObj)
print('**** Sort Dataframe rows based on a multiple columns ****')
dfObj = dfObj.sort_values(by =['Name', 'Marks'])
print("Contents of a Sorted Dataframe based on multiple columns 'Name' & 'Marks' : ")
print(dfObj)
print('**** Sort Dataframe rows based on a single column in Descending Order ****')
# Sort the rows of dataframe by column 'Name' in descending order
dfObj = dfObj.sort_values(by ='Name' , ascending=False)
print("Contents of Sorted Dataframe based on a column 'Name' in Descending Order : ")
print(dfObj)
print('**** Sort Dataframe rows based on a single column in place ****')
# Sort the rows of dataframe by column 'Name' inplace
dfObj.sort_values(by='Name' , inplace=True)
print("Contents of Sorted Dataframe based on a single column 'Name' inplace: ")
print(dfObj)
print('******** Sort columns of Dataframe based on a single or multiple rows ********')
# List of Tuples
matrix = [(222, 16, 23),
(333, 31, 11),
(444, 34, 11),
]
# Create a DataFrame object of 3X3 Matrix
dfObj = pd.DataFrame(matrix, index=list('abc'))
print("Original Dataframe: ")
print(dfObj)
# Sort columns of a dataframe based on a single row with index label 'b'
dfObj = dfObj.sort_values(by ='b', axis=1)
print("Contents of Sorted Dataframe based on a single row index label 'b' ")
print(dfObj)
# Sort columns of a dataframe in descending order based on a single row with index label 'b'
dfObj = dfObj.sort_values(by='b', axis=1, ascending=False)
print("Contents of Sorted Dataframe in descending order based on a single row index label 'b' ")
print(dfObj)
# Sort columns of a dataframe based on a multiple row with index labels 'b' & 'c'
dfObj = dfObj.sort_values(by =['b' , 'c' ], axis=1)
print("Contents of Sorted Dataframe based on multiple rows index label 'b' & 'c' ")
print(dfObj)
if __name__ == '__main__':
main()

References
https://thispointer.com/pandas-sort-rows-or-columns-in-dataframe-based-on-values-using-dataframe-sort_values/
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sort_values.html

Append existing excel sheet with new Dataframe using Python Pandas

def append_df_to_excel(filename, df, sheet_name='Sheet1', startrow=None,
                       truncate_sheet=False, 
                       **to_excel_kwargs):
    """
    Append a DataFrame [df] to existing Excel file [filename]
    into [sheet_name] Sheet.
    If [filename] doesn't exist, then this function will create it.

    Parameters:
      filename : File path or existing ExcelWriter
                 (Example: '/path/to/file.xlsx')
      df : dataframe to save to workbook
      sheet_name : Name of sheet which will contain DataFrame.
                   (default: 'Sheet1')
      startrow : upper left cell row to dump data frame.
                 Per default (startrow=None) calculate the last row
                 in the existing DF and write to the next row...
      truncate_sheet : truncate (remove and recreate) [sheet_name]
                       before writing DataFrame to Excel file
      to_excel_kwargs : arguments which will be passed to `DataFrame.to_excel()`
                        [can be dictionary]

    Returns: None
    """
    from openpyxl import load_workbook

    import pandas as pd

    # ignore [engine] parameter if it was passed
    if 'engine' in to_excel_kwargs:
        to_excel_kwargs.pop('engine')

    writer = pd.ExcelWriter(filename, engine='openpyxl')

    # Python 2.x: define [FileNotFoundError] exception if it doesn't exist 
    try:
        FileNotFoundError
    except NameError:
        FileNotFoundError = IOError


    try:
        # try to open an existing workbook
        writer.book = load_workbook(filename)

        # get the last row in the existing Excel sheet
        # if it was not specified explicitly
        if startrow is None and sheet_name in writer.book.sheetnames:
            startrow = writer.book[sheet_name].max_row

        # truncate sheet
        if truncate_sheet and sheet_name in writer.book.sheetnames:
            # index of [sheet_name] sheet
            idx = writer.book.sheetnames.index(sheet_name)
            # remove [sheet_name]
            writer.book.remove(writer.book.worksheets[idx])
            # create an empty sheet [sheet_name] using old index
            writer.book.create_sheet(sheet_name, idx)

        # copy existing sheets
        writer.sheets = {ws.title:ws for ws in writer.book.worksheets}
    except FileNotFoundError:
        # file does not exist yet, we will create it
        pass

    if startrow is None:
        startrow = 0

    # write out the new sheet
    df.to_excel(writer, sheet_name, startrow=startrow, **to_excel_kwargs)

    # save the workbook
    writer.save()

References
https://stackoverflow.com/questions/38074678/append-existing-excel-sheet-with-new-dataframe-using-python-pandas