import cv2, datetime, os import numpy as np from copy import deepcopy from matplotlib import pyplot as plt from . import Algorithm class InvisCloak (Algorithm): """ init function """ def __init__(self): # Number of buffered images self.n = 5 # Picture buffer self.picture_buffer = [] # Middle value image built of buffer images # Includes noice reduction and histogram spread self.middle_value_picture = None # Buffer for background image self.background = None # Clean up results folder folder_path = os.path.join("results") for filename in os.listdir(folder_path): file_path = os.path.join(folder_path, filename) if os.path.isfile(file_path): os.unlink(file_path) """ Processes the input image""" def process(self, img): """ 2.1 Vorverarbeitung """ """ 2.1.1 Rauschreduktion """ plotNoise = False # Schaltet die Rauschvisualisierung ein if plotNoise: self._plotNoise(img, "Rauschen vor Korrektur") img = self._211_Rauschreduktion(img) if plotNoise: self._plotNoise(img, "Rauschen nach Korrektur") """ 2.1.2 HistogrammSpreizung """ img = self._212_HistogrammSpreizung(img) """ 2.2 Farbanalyse """ """ 2.2.1 RGB """ #self._221_RGB(img) """ 2.2.2 HSV """ #self._222_HSV(img) """ 2.3 Segmentierung und Bildmodifikation """ img = self._23_SegmentUndBildmodifizierung(img) return img """ Reacts on mouse callbacks """ def mouse_callback(self, event, x, y, flags, param): if event == cv2.EVENT_LBUTTONUP: print("A Mouse click happend! at position", x, y) # Stores the current image to data folder cv2.imwrite(f"results/{datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S')}_original_image.png", self.picture_buffer[self.n - 1]) # Create RGB histogram self._221_RGB(self.middle_value_picture) # Create HSV histogram self._222_HSV(self.middle_value_picture) # Get binary mask and write it to file binary_mask = self._23_SegmentUndBildmodifizierung(self.middle_value_picture, True) cv2.imwrite(f"results/{datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S')}_binary_mask.png", binary_mask) elif event == cv2.EVENT_MBUTTONUP: # Save current image as background cv2.imwrite(f"results/background.png", self.picture_buffer[self.n - 1]) self.background = cv2.imread("results/background.png") def _plotNoise(self, img, name:str): height, width = np.array(img.shape[:2]) centY = (height / 2).astype(int) centX = (width / 2).astype(int) cutOut = 5 tmpImg = deepcopy(img) tmpImg = tmpImg[centY - cutOut:centY + cutOut, centX - cutOut:centX + cutOut, :] outSize = 500 tmpImg = cv2.resize(tmpImg, (outSize, outSize), interpolation=cv2.INTER_NEAREST) cv2.imshow(name, tmpImg) cv2.waitKey(1) def _211_Rauschreduktion(self, img): """ Hier steht Ihr Code zu Aufgabe 2.1.1 (Rauschunterdrückung) - Implementierung Mittelwertbildung über N Frames """ self.picture_buffer.append(img) if len(self.picture_buffer) < self.n: # If number of buffered images < defined buffer size n, return current image return img elif len(self.picture_buffer) > self.n: # If number of buffered images > defined buffer size n, remove oldest image self.picture_buffer.pop(0) # Reduce noise, return result image return np.mean(self.picture_buffer, axis=0).astype(np.uint8) def _212_HistogrammSpreizung(self, img): """ Hier steht Ihr Code zu Aufgabe 2.1.2 (Histogrammspreizung) - Transformation HSV - Histogrammspreizung berechnen - Transformation BGR """ # Convert brg image to hsv image hsv_image = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Get hsv parts h, s, v = cv2.split(hsv_image) # Calc histogram spread v = cv2.equalizeHist(v) # Merge histogram spread to image hsv_stretched = cv2.merge([h, s, v]) # Convert hsv image to brg and store result to member variable self.middle_value_picture = cv2.cvtColor(hsv_stretched, cv2.COLOR_HSV2BGR) # Return brg result image return self.middle_value_picture def _221_RGB(self, img, colorspectrum = "bgr"): """ Hier steht Ihr Code zu Aufgabe 2.2.1 (RGB) - Histogrammberechnung und Analyse """ # Names of the colors in histogram channels = ["b", "g", "r"] # Calc histogram for index, channel_name in enumerate(channels): hist = cv2.calcHist([img], [index], None, [256], [0, 256]) plt.plot(hist, color=channel_name) plt.xlim([0, 256]) # Save histogram, clear cache plt.savefig(f"results/{datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S')}_histogram_{colorspectrum}.png") plt.clf() def _222_HSV(self, img): """ Hier steht Ihr Code zu Aufgabe 2.2.2 (HSV) - Histogrammberechnung und Analyse im HSV-Raum """ # Convert image to hsv, call _221_RGB to create histogram self._221_RGB(cv2.cvtColor(img, cv2.COLOR_BGR2HSV), "hsv") def _23_SegmentUndBildmodifizierung (self, img, save_binary_mask = False): """ Hier steht Ihr Code zu Aufgabe 2.3.1 (StatischesSchwellwertverfahren) - Binärmaske erstellen """ # Convert BGR -> HSV hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Area 1: H = 0-10 (strong Rot) lower_red1 = np.array([0, 100, 50]) upper_red1 = np.array([0, 255, 255]) # Area 2: H = 169-179 (red-violet) lower_red2 = np.array([171, 100, 50]) upper_red2 = np.array([179, 255, 255]) # Create binary mask for both red areas mask1 = cv2.inRange(hsv, lower_red1, upper_red1) mask2 = cv2.inRange(hsv, lower_red2, upper_red2) # Combine both masks mask = cv2.bitwise_or(mask1, mask2) """ Hier steht Ihr Code zu Aufgabe 2.3.2 (Binärmaske) - Binärmaske optimieren mit Opening/Closing - Wahl größte zusammenhängende Region """ # Optimizing mask with opening and closing kernel = np.ones((5, 5), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # Select biggest connected area cnts, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) if cnts: c = max(cnts, key=cv2.contourArea) new_mask = np.zeros_like(mask) cv2.drawContours(new_mask, [c], -1, color = 255, thickness = -1) mask = new_mask else: mask = np.zeros_like(mask) """ Hier steht Ihr Code zu Aufgabe 2.3.3 (Bildmodifizerung) - Hintergrund mit Mausklick definieren - Ersetzen des Hintergrundes """ # Return image if no background is set if self.background is None: return img # 3-channel mask for binary operations mask_3ch = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) # Background are: Get from save background image background_part = cv2.bitwise_and(self.background, mask_3ch) # Foreground area: Extract from current image foreground_part = cv2.bitwise_and(img, cv2.bitwise_not(mask_3ch)) # Merge both areas output = cv2.add(background_part, foreground_part) return output