Files
digitale-bildverarbeitung-l…/CV-App/algorithms/invis_cloak.py
2025-07-03 17:55:33 +02:00

242 lines
7.9 KiB
Python

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