borakol commited on
Commit
bf0a759
·
verified ·
1 Parent(s): 2864a01

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -0
app.py ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import time
4
+
5
+ class CameraAnalyzer:
6
+ def __init__(self, camera_source=0):
7
+ # Kamera başlatma
8
+ self.cap = cv2.VideoCapture(camera_source)
9
+ if not self.cap.isOpened():
10
+ raise ValueError("Kamera açılamadı!")
11
+
12
+ # Çözünürlük ayarları (isteğe bağlı, performans için düşürülebilir)
13
+ self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
14
+ self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
15
+
16
+ # Durum değişkenleri
17
+ self.accumulated_frame = None
18
+ self.frame_count = 0
19
+ self.is_calibrating = False
20
+ self.mode = "LIVE" # LIVE, DARK_CALIB, FLAT_CALIB, SPN_VIEW
21
+
22
+ # Tespit edilen hatalı piksellerin listesi (koordinat olarak)
23
+ self.hot_pixels = [] # Karanlıkta parlayanlar
24
+ self.dead_pixels = [] # Aydınlıkta sönenler
25
+
26
+ # SPN analizi için matrisler
27
+ self.spn_pattern = None
28
+
29
+ def capture_frame(self):
30
+ ret, frame = self.cap.read()
31
+ if not ret:
32
+ return None
33
+ return frame
34
+
35
+ def process_calibration(self, frame, mode):
36
+ """
37
+ Kalibrasyon sırasında kareleri toplar ve ortalamasını alır.
38
+ Bu yöntem rastgele gürültüyü (random noise) azaltarak
39
+ sabit gürültüyü (FPN/SPN) ortaya çıkarır.
40
+ """
41
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY).astype(np.float32)
42
+
43
+ if self.accumulated_frame is None:
44
+ self.accumulated_frame = gray
45
+ else:
46
+ # Hareketli ortalama (Running Average)
47
+ cv2.accumulateWeighted(gray, self.accumulated_frame, 0.1)
48
+
49
+ self.frame_count += 1
50
+ return cv2.convertScaleAbs(self.accumulated_frame)
51
+
52
+ def analyze_dark_frame(self, avg_frame, threshold=20):
53
+ """
54
+ Karanlık çerçeve analizi:
55
+ Simsiyah olması gereken yerde parlayan pikselleri (Hot Pixels) bulur.
56
+ """
57
+ # Eşik değerinin üzerindeki pikselleri bul
58
+ _, thresh = cv2.threshold(avg_frame, threshold, 255, cv2.THRESH_BINARY)
59
+ coordinates = cv2.findNonZero(thresh)
60
+
61
+ detected = []
62
+ if coordinates is not None:
63
+ for coord in coordinates:
64
+ detected.append((coord[0][0], coord[0][1]))
65
+ return detected
66
+
67
+ def analyze_flat_frame(self, avg_frame, threshold=200):
68
+ """
69
+ Düz alan (beyaz) analizi:
70
+ Beyaz olması gereken yerde siyah kalan pikselleri (Dead Pixels) bulur.
71
+ """
72
+ # Eşik değerinin altındaki pikselleri bul (Beklenen çok parlak, gelen karanlık)
73
+ # Not: Threshold ortam ışığına göre ayarlanmalıdır.
74
+ _, thresh = cv2.threshold(avg_frame, threshold, 255, cv2.THRESH_BINARY_INV)
75
+ coordinates = cv2.findNonZero(thresh)
76
+
77
+ detected = []
78
+ if coordinates is not None:
79
+ for coord in coordinates:
80
+ detected.append((coord[0][0], coord[0][1]))
81
+ return detected
82
+
83
+ def extract_spn(self, avg_frame):
84
+ """
85
+ Sensor Pattern Noise (SPN) Çıkarımı:
86
+ Basitleştirilmiş yöntem: Görüntüden, görüntünün yumuşatılmış halini çıkarırız.
87
+ Geriye kalan yüksek frekanslı detaylar sensör gürültüsü ve ince dokulardır.
88
+ """
89
+ # 1. Gürültüden arındırılmış (denoised) versiyonu oluştur (Gaussian Blur ile)
90
+ float_avg = avg_frame.astype(np.float32)
91
+ denoised = cv2.GaussianBlur(float_avg, (5, 5), 0)
92
+
93
+ # 2. Orijinal ortalamadan yumuşatılmış hali çıkar (Geriye gürültü kalır)
94
+ noise_residue = float_avg - denoised
95
+
96
+ # 3. Görselleştirme için normalize et (0-255 arasına çek ve kontrastı artır)
97
+ # SPN normalde çıplak gözle görülmez, bu yüzden güçlendiriyoruz.
98
+ spn_vis = cv2.normalize(noise_residue, None, 0, 255, cv2.NORM_MINMAX)
99
+ spn_vis = cv2.convertScaleAbs(spn_vis, alpha=5.0, beta=128) # Kontrast artır
100
+
101
+ return spn_vis
102
+
103
+ def run(self):
104
+ print("--- KAMERA SENSÖR ANALİZİ ---")
105
+ print("'d': Karanlık Mod Kalibrasyonu (Lensi Kapatın)")
106
+ print("'f': Düz Alan Kalibrasyonu (Beyaz Bir Yere Tutun)")
107
+ print("'s': SPN (Sensör Gürültüsü) Görünümüne Geç")
108
+ print("'r': Reset / Canlı Mod")
109
+ print("'q': Çıkış")
110
+
111
+ while True:
112
+ frame = self.capture_frame()
113
+ if frame is None:
114
+ break
115
+
116
+ display_frame = frame.copy()
117
+ h, w = frame.shape[:2]
118
+
119
+ # Tuş kontrolleri
120
+ key = cv2.waitKey(1) & 0xFF
121
+
122
+ if key == ord('d'): # Karanlık Kalibrasyon Başlat
123
+ self.mode = "DARK_CALIB"
124
+ self.accumulated_frame = None
125
+ self.frame_count = 0
126
+ self.hot_pixels = []
127
+ print("Karanlık kalibrasyon başladı. Lütfen lensi kapatın.")
128
+
129
+ elif key == ord('f'): # Düz Alan Kalibrasyon Başlat
130
+ self.mode = "FLAT_CALIB"
131
+ self.accumulated_frame = None
132
+ self.frame_count = 0
133
+ self.dead_pixels = []
134
+ print("Düz alan kalibrasyonu başladı. Beyaz bir yüzeye tutun.")
135
+
136
+ elif key == ord('s'): # SPN Görünümü
137
+ if self.accumulated_frame is not None:
138
+ self.mode = "SPN_VIEW"
139
+ else:
140
+ print("Önce bir kalibrasyon (d veya f) yaparak veri toplayın.")
141
+
142
+ elif key == ord('r'): # Reset
143
+ self.mode = "LIVE"
144
+ self.accumulated_frame = None
145
+
146
+ elif key == ord('q'): # Çıkış
147
+ break
148
+
149
+ # MODLARA GÖRE İŞLEMLER
150
+ if self.mode == "DARK_CALIB":
151
+ avg = self.process_calibration(frame, "dark")
152
+
153
+ # Anlık analiz (örneğin 30 kare sonra analiz yap)
154
+ if self.frame_count > 30:
155
+ self.hot_pixels = self.analyze_dark_frame(avg, threshold=15)
156
+ cv2.putText(display_frame, "Analiz Tamamlandi!", (10, 60),
157
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
158
+ self.mode = "LIVE" # Otomatik olarak canlıya dön
159
+
160
+ cv2.putText(display_frame, f"Karanlik Kalibrasyon: {self.frame_count}/30", (10, 30),
161
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
162
+
163
+ elif self.mode == "FLAT_CALIB":
164
+ avg = self.process_calibration(frame, "flat")
165
+
166
+ if self.frame_count > 30:
167
+ # Ortalama parlaklığın %50'sinin altındakileri ölü kabul et
168
+ mean_val = np.mean(avg)
169
+ threshold = mean_val * 0.5
170
+ self.dead_pixels = self.analyze_flat_frame(avg, threshold=threshold)
171
+ cv2.putText(display_frame, "Analiz Tamamlandi!", (10, 60),
172
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
173
+ self.mode = "LIVE"
174
+
175
+ cv2.putText(display_frame, f"Duz Alan Kalibrasyon: {self.frame_count}/30", (10, 30),
176
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
177
+
178
+ elif self.mode == "SPN_VIEW":
179
+ # Birikmiş kareden SPN çıkar
180
+ if self.accumulated_frame is not None:
181
+ avg_int = cv2.convertScaleAbs(self.accumulated_frame)
182
+ spn_vis = self.extract_spn(avg_int)
183
+
184
+ # SPN'i renkliye çevirip ekrana bas (gri tonlamalı)
185
+ display_frame = cv2.cvtColor(spn_vis, cv2.COLOR_GRAY2BGR)
186
+ cv2.putText(display_frame, "SPN (Sensor Pattern Noise) Gorunumu", (10, 30),
187
+ cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)
188
+
189
+ # Canlı modda hatalı pikselleri işaretle
190
+ if self.mode == "LIVE":
191
+ # Hot Pixels (Kırmızı Daire)
192
+ for x, y in self.hot_pixels:
193
+ cv2.circle(display_frame, (x, y), 5, (0, 0, 255), 1)
194
+ # Daha belirgin olması için ok işareti de eklenebilir
195
+
196
+ # Dead Pixels (Mavi Daire)
197
+ for x, y in self.dead_pixels:
198
+ cv2.circle(display_frame, (x, y), 5, (255, 0, 0), 1)
199
+
200
+ info_text = f"Hot: {len(self.hot_pixels)} | Dead: {len(self.dead_pixels)}"
201
+ cv2.putText(display_frame, info_text, (10, h - 20),
202
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1)
203
+
204
+ cv2.imshow("Sensor Analiz", display_frame)
205
+
206
+ self.cap.release()
207
+ cv2.destroyAllWindows()
208
+
209
+ if __name__ == "__main__":
210
+ app = CameraAnalyzer()
211
+ app.run()