borakol commited on
Commit
f68f2e8
·
verified ·
1 Parent(s): 9252736

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +139 -199
app.py CHANGED
@@ -1,211 +1,151 @@
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()
 
1
+ import cv2
2
  import numpy as np
3
+ import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ class CameraAnalyzerState:
6
+ def __init__(self):
7
  self.accumulated_frame = None
8
  self.frame_count = 0
9
+ self.mode = "LIVE" # LIVE, DARK_CALIB, FLAT_CALIB, SPN_VIEW
10
+ self.hot_pixels = []
11
+ self.dead_pixels = []
12
+ self.msg = "Hazır. Canlı mod."
13
+
14
+ def reset(self):
15
+ self.accumulated_frame = None
16
+ self.frame_count = 0
17
+ self.mode = "LIVE"
18
+ self.msg = "Sıfırlandı."
19
+
20
+ # Global state (Tek kullanıcı demo için. Çoklu kullanıcı için gr.State kullanılmalı ama basitlik adına global tutuyoruz)
21
+ analyzer = CameraAnalyzerState()
22
+
23
+ def process_frame(frame):
24
+ global analyzer
25
+
26
+ if frame is None:
27
+ return None
28
+
29
+ # Görüntüyü çevir (Mirror effect)
30
+ frame = cv2.flip(frame, 1)
31
+ display_frame = frame.copy()
32
+
33
+ # Griye çevir (işlemler için)
34
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY).astype(np.float32)
35
+
36
+ # --- DURUM YÖNETİMİ ---
37
+ if analyzer.mode == "DARK_CALIB" or analyzer.mode == "FLAT_CALIB":
38
+ if analyzer.accumulated_frame is None:
39
+ analyzer.accumulated_frame = gray
40
  else:
41
+ cv2.accumulateWeighted(gray, analyzer.accumulated_frame, 0.1)
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
+ analyzer.frame_count += 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ # 30 kare toplandıysa analizi yap
46
+ if analyzer.frame_count > 30:
47
+ avg_frame = cv2.convertScaleAbs(analyzer.accumulated_frame)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ if analyzer.mode == "DARK_CALIB":
50
+ # Hot Pixel Analizi
51
+ _, thresh = cv2.threshold(avg_frame, 25, 255, cv2.THRESH_BINARY)
52
+ coords = cv2.findNonZero(thresh)
53
+ analyzer.hot_pixels = [(p[0][0], p[0][1]) for p in coords] if coords is not None else []
54
+ analyzer.msg = f"Karanlık Kalibrasyon Bitti! {len(analyzer.hot_pixels)} sıcak piksel bulundu."
 
 
 
 
 
 
 
55
 
56
+ elif analyzer.mode == "FLAT_CALIB":
57
+ # Dead Pixel Analizi
58
+ mean_val = np.mean(avg_frame)
59
+ threshold_val = mean_val * 0.6
60
+ _, thresh = cv2.threshold(avg_frame, threshold_val, 255, cv2.THRESH_BINARY_INV)
61
+ coords = cv2.findNonZero(thresh)
62
+ analyzer.dead_pixels = [(p[0][0], p[0][1]) for p in coords] if coords is not None else []
63
+ analyzer.msg = f"Düz Alan Kalibrasyonu Bitti! {len(analyzer.dead_pixels)} ölü piksel bulundu."
64
+
65
+ # Analiz bitince Live moda dön ama verileri sakla
66
+ analyzer.mode = "LIVE"
67
+ analyzer.accumulated_frame = None
68
+ analyzer.frame_count = 0
69
+ else:
70
+ analyzer.msg = f"Kalibrasyon yapılıyor... {analyzer.frame_count}/30"
71
+
72
+ # --- GÖRSELLEŞTİRME ---
73
+
74
+ # SPN Modu (Gürültü Görme)
75
+ if analyzer.mode == "SPN_VIEW":
76
+ # SPN için anlık kareyi yumuşatıp çıkarıyoruz (basitleştirilmiş anlık SPN)
77
+ # Gerçek SPN birikmiş kare ister ama webcam akışında anlık göstermek daha efektiftir
78
+ float_img = gray
79
+ denoised = cv2.GaussianBlur(float_img, (5, 5), 0)
80
+ residue = float_img - denoised
81
+ spn_vis = cv2.normalize(residue, None, 0, 255, cv2.NORM_MINMAX)
82
+ spn_vis = cv2.convertScaleAbs(spn_vis, alpha=5.0, beta=128)
83
+ display_frame = cv2.cvtColor(spn_vis, cv2.COLOR_GRAY2BGR)
84
+ cv2.putText(display_frame, "SPN MODU", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
85
+
86
+ # İşaretlemeler (Live Modda)
87
+ else:
88
+ # Hot Pixels (Kırmızı)
89
+ for x, y in analyzer.hot_pixels:
90
+ cv2.circle(display_frame, (x, y), 8, (255, 0, 0), 2) # Kırmızı (RGB'de Gradio BGR alabilir dikkat)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
+ # Dead Pixels (Mavi)
93
+ for x, y in analyzer.dead_pixels:
94
+ cv2.circle(display_frame, (x, y), 8, (0, 0, 255), 2) # Mavi
95
+
96
+ # Bilgi mesajı
97
+ cv2.putText(display_frame, analyzer.msg, (10, display_frame.shape[0] - 20),
98
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
99
+
100
+ # OpenCV BGR formatından RGB formatına çevir (Gradio için)
101
+ return cv2.cvtColor(display_frame, cv2.COLOR_BGR2RGB)
102
+
103
+ def set_mode_dark():
104
+ analyzer.mode = "DARK_CALIB"
105
+ analyzer.accumulated_frame = None
106
+ analyzer.frame_count = 0
107
+ analyzer.msg = "Lensi kapatin..."
108
+ return
109
+
110
+ def set_mode_flat():
111
+ analyzer.mode = "FLAT_CALIB"
112
+ analyzer.accumulated_frame = None
113
+ analyzer.frame_count = 0
114
+ analyzer.msg = "Beyaz bir duvara tutun..."
115
+ return
116
+
117
+ def set_mode_spn():
118
+ analyzer.mode = "SPN_VIEW"
119
+ analyzer.msg = "SPN Modu"
120
+ return
121
+
122
+ def reset_all():
123
+ analyzer.reset()
124
+ return
125
+
126
+ # --- ARAYÜZ ---
127
+ with gr.Blocks() as demo:
128
+ gr.Markdown("# Kamera Dead Pixel & SPN Analizi")
129
+ gr.Markdown("Bu araç tarayıcı kameranızı kullanarak sensör analizi yapar.")
130
+
131
+ with gr.Row():
132
+ start_dark = gr.Button("1. Karanlık Kalibrasyon (Hot Pixel)")
133
+ start_flat = gr.Button("2. Düz Alan Kalibrasyon (Dead Pixel)")
134
+ start_spn = gr.Button("3. SPN Modu (Gürültü)")
135
+ btn_reset = gr.Button("Sıfırla")
136
+
137
+ # Webcam Input (Streaming=True sürekli akış sağlar)
138
+ image_input = gr.Image(sources=["webcam"], streaming=True, label="Kamera")
139
+ image_output = gr.Image(label="Analiz Sonucu")
140
+
141
+ # Buton olayları
142
+ start_dark.click(fn=set_mode_dark, inputs=None, outputs=None)
143
+ start_flat.click(fn=set_mode_flat, inputs=None, outputs=None)
144
+ start_spn.click(fn=set_mode_spn, inputs=None, outputs=None)
145
+ btn_reset.click(fn=reset_all, inputs=None, outputs=None)
146
+
147
+ # Akış döngüsü
148
+ image_input.stream(fn=process_frame, inputs=image_input, outputs=image_output, time_limit=600)
149
 
150
  if __name__ == "__main__":
151
+ demo.launch()