diff --git a/.gitignore b/.gitignore
index ad61a4e62384c2f4bda3ecc95eb7e2695645a508..a5fbee1f4b78a0abe145778cb0ce7bf71b5f0503 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 # Videos NICHT hochladen
-/Videomaterial
\ No newline at end of file
+/Videomaterial
+
+/__pycache__
\ No newline at end of file
diff --git a/filter_pipeline.py b/filter_pipeline.py
new file mode 100644
index 0000000000000000000000000000000000000000..c44ffcd19b0089d7b5177bc64463c813fac2f47d
--- /dev/null
+++ b/filter_pipeline.py
@@ -0,0 +1,117 @@
+import cv2
+import numpy as np
+import matplotlib.pyplot as plt
+import time
+from datetime import datetime
+import pandas as pd
+
+VIDEO = 'Videomaterial/WIN_20230414_13_41_55_Pro.mp4'
+capture = cv2.VideoCapture(VIDEO)
+
+
+last = None
+frame = None
+diff = None
+window = 'Filter'
+
+# Einstellungen
+min_threshold  = 30
+max_threshold  = 110
+img_threshold  = 100
+line_threshold = 30
+
+spanne = 2
+
+def overlay_imgs(base, top):
+    topgray = cv2.cvtColor(top, cv2.COLOR_RGB2GRAY)
+
+    _, mask = cv2.threshold(topgray, 10, 255, cv2.THRESH_BINARY)
+    mask_inv = cv2.bitwise_not(mask)
+    # Now black-out the area of overlay
+    img1_bg = cv2.bitwise_and(base,base,mask = mask_inv)
+    # Take only region of from logo image.
+    img2_fg = cv2.bitwise_and(top,top,mask = mask)
+
+    return cv2.add(img1_bg, img2_fg)
+
+def nothing_cb(val):
+    pass
+
+# To control the Size of the Disply 
+cv2.namedWindow(window, cv2.WINDOW_AUTOSIZE)
+cv2.createTrackbar('Line Threshold: ', window, line_threshold, 100, nothing_cb)
+
+import filters
+pipeline = [
+    ('Original', filters.none),
+    ('Gray scale', filters.grayscale),
+    ('Contrast and Blur', filters.medianBlur),
+    ('Video Diff', filters.video_absdiff),
+    ('Canny edge detection', filters.filter_canny),
+    ('Morph close', filters.filter_close),
+    #('Morph open', filters.filter_open),
+    ('Point extraction', filters.points_extract),
+    ('Polyfit lines', filters.points_overlay)
+]
+
+state = {} # Empty dictionary to store filters state
+
+info = {
+    'abs_diff': 5,       # 5 images for difference,
+    'dim': (1920, 1080), #
+    'params': {}
+}
+
+result = None
+visible_filter_idx = 0
+while capture.isOpened():
+    # ret is the stat of the reading
+    ret, frame = capture.read()
+    if ret == True:
+        frame, _ = filters.resize(None, frame, None)
+
+        # Apply
+        info['params']['line'] = cv2.getTrackbarPos('Line Threshold: ', window)
+
+        result = frame
+        for i, (name, filter) in enumerate(pipeline):
+            # Apply each filter
+            result, overlay = filter(info, result, state)
+
+            if result is None:
+                break
+
+            if visible_filter_idx == i:
+                image = result.copy()
+
+                if overlay:
+                    image = overlay_imgs(frame, image)
+
+                cv2.putText(image, f'Filter #{i}: {name}', (10, 30), cv2.FONT_HERSHEY_PLAIN, 
+                            1, (255, 0, 0), 2, cv2.LINE_AA)
+                cv2.imshow('Filter', image)
+    
+
+
+        code = cv2.waitKey(33) & 0xFF
+        if code == ord('s'):
+            now = datetime.now()
+            str = now.strftime("%d_%m_%Y_%H_%M_%S")
+            cv2.imwrite(f'Filter/IMG_{str}.png', result)
+        elif code == ord('d'):
+            visible_filter_idx += 1
+            if visible_filter_idx >= len(pipeline):
+                visible_filter_idx = len(pipeline) - 1
+        elif code == ord('a'):    
+            visible_filter_idx -= 1
+            if visible_filter_idx < 0:
+                visible_filter_idx = 0
+        elif code & 0xFF == ord('q'):
+            break
+
+    else:
+        break
+
+capture.release()
+
+cv2.destroyAllWindows()
\ No newline at end of file
diff --git a/filters.py b/filters.py
new file mode 100644
index 0000000000000000000000000000000000000000..af1770aee55ce7515efb5fe0e9264cf69075872f
--- /dev/null
+++ b/filters.py
@@ -0,0 +1,163 @@
+import cv2 as cv
+import numpy as np
+import pandas as pd
+
+def none(info, image, state):
+    return image, False
+
+# Resize image to 1280x720 pixels
+def resize(info, image, state):
+    res = cv.resize(image, (1280, 720))
+    return res, False
+
+
+# Convert to Gray scale image
+def grayscale(info, image, state):
+    res = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
+    return res, False
+
+def medianBlur(info, image, state):
+    # median of all the pixels under the kernel area
+    blur = cv.medianBlur(image, 7)
+    # adding tow images 
+    sharp = cv.addWeighted(image, 1.5, blur, -0.5, 0.0)
+    return sharp, False
+
+# def plot_points(x, y, px, py):
+#     fig = plt.figure()
+#     ax = fig.add_subplot()
+#     ax.scatter(px, py, c='r')
+#     ax.plot(x, y)
+#     ax.set_xlim([0, 1280])
+#     ax.set_ylim([720, 0])
+#     plt.show()
+
+spanne = 5
+
+def find_points(image):
+    indices = np.where(image > 0)
+    if (indices[1].size > 0):
+        x_so = indices[1]
+        y_so = indices[0]
+        
+        list_xy = np.column_stack((x_so, y_so)).astype(np.int32)
+        # list_xy = np.sort(list_xy, axis=0)
+        # print( list_xy)
+        
+        df = pd.DataFrame(list_xy,columns=['x','y'])
+
+        df = df.sort_values(by=['x'], ascending=True)
+
+        n_list = []
+        
+        df_un = df.x.unique()                    
+        for el in df_un[::2]:
+            
+            med = (df.y.where(df.x >= el-spanne).where(el+spanne >= df.x)).median()
+            n_list.append([el,med])
+          
+        
+        n_list = np.array(n_list).astype(np.int32)
+        return n_list
+
+    return None
+    
+
+def polyfit(n_list):
+    if n_list is not None:
+        p = np.polyfit(n_list[:,0], n_list[:,1], 6)
+        x = np.arange(n_list[:,0][0], n_list[:,0][-1], 1)
+        y = np.polyval(p,x)
+        points = np.column_stack((x, y)).astype(np.int32)
+        return points 
+    
+    return None
+
+min_threshold  = 30
+max_threshold  = 110
+
+def filter_canny(info, image, state):
+    image = cv.Canny(image, min_threshold, max_threshold)
+    return image, False
+
+def filter_open(info, image, state):
+    ksize = (3,3)
+    # kernel = np.ones(ksize,np.uint8)
+    kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, ksize)
+    image = cv.morphologyEx(image, cv.MORPH_OPEN, kernel)
+
+    return image, False
+
+def filter_close(info, image, state):
+    ksize = (3,3)
+    # kernel = np.ones(ksize,np.uint8)
+    kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, ksize)
+    image = cv.morphologyEx(image, cv.MORPH_CLOSE, kernel)
+
+    return image, False
+
+
+def points_extract(info, image, state):
+    points = find_points(image)
+    overlay = np.zeros((image.shape[0], image.shape[1], 3), np.uint8)
+
+    for y, x in points:
+        if x < image.shape[0] and  y < image.shape[1]:
+            overlay[x, y] = (255, 0, 0)
+        
+
+    #cv.polylines(overlay, [points], False, (255, 0, 0), thickness=1)
+
+    state['points'] = points
+    return overlay, False
+
+
+def points_overlay(info, image, state):
+    points = state['points']
+    poly_points = polyfit(points)
+
+    overlay = np.zeros((image.shape[0], image.shape[1], 3), np.uint8)
+    # draw a polygon on the image
+    cv.polylines(overlay, [poly_points], False, (255, 0, 0), thickness=5)
+    return overlay, True
+
+def filter_all(info, image, state):
+    image = image.copy()
+    
+    # construct a rectangular kernel from the current size /  rect shaped kernel
+    kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (1,1)) 
+    
+    # Opening operation
+    image = cv.morphologyEx(image, cv.MORPH_OPEN, kernel)
+    
+    # perform erosion on the image
+    image = cv.erode(image, (3,3))
+    
+    # Closing operation / closing small holes
+    # image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, (1,1))
+    image = cv.morphologyEx(image, cv.MORPH_CLOSE, (5,5))
+  #  # image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, (4,4))
+  
+    # dilation
+    kernel2 = cv.getStructuringElement(cv.MORPH_ELLIPSE, (2,2))
+    image = cv.dilate(image,kernel2,iterations = 1)
+    
+    # Use canny edge detection
+    image = cv.Canny(image, min_threshold, max_threshold)
+    
+    points = find_points(image)
+    overlay = np.zeros((image.shape[0], image.shape[1], 3), np.uint8)
+    # draw a polygon on the image
+    cv.polylines(overlay, [points], False, (255, 0, 0), thickness=6)
+    return overlay, True
+
+
+def video_absdiff(info, image, state):
+    if 'last' not in state or state['last'] is None:
+        state['last'] = image
+        return None, False
+
+    diff = cv.absdiff(image, state['last'])
+    state['last'] = image
+    return diff, False
+