petertulip86 commited on
Commit
be1d691
·
verified ·
1 Parent(s): 36b97d9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -140
app.py CHANGED
@@ -2,15 +2,12 @@ import cv2
2
  import numpy as np
3
  import gradio as gr
4
 
5
- def hsv_filter(image,
6
- h_low=0, h_high=179,
7
- s_low=0, s_high=255,
8
- v_low=0, v_high=255):
9
  """
10
  對輸入的圖像應用 HSV 過濾
11
 
12
  Args:
13
- image: 輸入的圖像(來自網路攝像頭或上傳)
14
  h_low, h_high: Hue(色調)的最低和最高值
15
  s_low, s_high: Saturation(飽和度)的最低和最高值
16
  v_low, v_high: Value(亮度)的最低和最高值
@@ -19,10 +16,18 @@ def hsv_filter(image,
19
  原始圖像、HSV 過濾遮罩和過濾後的結果
20
  """
21
  if image is None:
 
22
  return None, None, None
23
 
 
 
 
 
 
 
 
24
  # 將圖像轉換為 HSV 色彩空間
25
- hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
26
 
27
  # 設置 HSV 過濾範圍
28
  lower = np.array([h_low, s_low, v_low])
@@ -32,160 +37,168 @@ def hsv_filter(image,
32
  mask = cv2.inRange(hsv, lower, upper)
33
 
34
  # 使用遮罩從原始圖像中提取物體
35
- result = cv2.bitwise_and(image, image, mask=mask)
 
 
 
36
 
37
  # 將遮罩轉換為 RGB 以便在 Gradio 中顯示
38
  mask_rgb = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)
39
 
40
- return image, mask_rgb, result
 
 
 
41
 
42
- def process_webcam(image, h_low, h_high, s_low, s_high, v_low, v_high):
43
  """
44
- 處理網路攝像頭的輸入
45
-
46
- Args:
47
- image: 來自網路攝像頭的圖像
48
- h_low, h_high, s_low, s_high, v_low, v_high: HSV 過濾參數
49
-
50
- Returns:
51
- 處理後的圖像結果(原始、遮罩、過濾後)
52
  """
53
- # Gradio 的 webcam 輸入是 RGB 格式,OpenCV 使用 BGR
54
- # 所以需要轉換顏色順序
55
- image_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
56
-
57
- # 應用 HSV 過濾
58
- orig, mask, result = hsv_filter(
59
- cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB), # 轉回 RGB 給過濾函數
60
- h_low, h_high, s_low, s_high, v_low, v_high
61
- )
62
-
63
- return orig, mask, result
 
 
 
 
 
 
64
 
65
  def process_image(image, h_low, h_high, s_low, s_high, v_low, v_high):
66
  """
67
- 處理上傳的圖像
68
-
69
- Args:
70
- image: 上傳的圖像
71
- h_low, h_high, s_low, s_high, v_low, v_high: HSV 過濾參數
72
-
73
- Returns:
74
- 處理後的圖像結果(原始、遮罩、過濾後)
75
  """
76
  if image is None:
77
- return None, None, None
 
78
 
79
  return hsv_filter(image, h_low, h_high, s_low, s_high, v_low, v_high)
80
 
81
- # 建立 Gradio 界面
82
  with gr.Blocks(title="HSV 顏色過濾器") as demo:
83
  gr.Markdown("# HSV 顏色過濾器")
84
- gr.Markdown("使用滑桿調整 HSV 值範圍,實時過濾圖像中的顏色")
85
-
86
- with gr.Tab("網路攝像頭"):
87
- with gr.Row():
88
- # 網路攝像頭輸入
89
- webcam_input = gr.Image(source="webcam", streaming=True, label="攝像頭輸入")
90
-
91
- with gr.Row():
92
- # HSV 滑桿控制(用於網路攝像頭)
93
- with gr.Column():
94
- h_low_webcam = gr.Slider(0, 179, 0, step=1, label="H Low")
95
- h_high_webcam = gr.Slider(0, 179, 179, step=1, label="H High")
96
- with gr.Column():
97
- s_low_webcam = gr.Slider(0, 255, 0, step=1, label="S Low")
98
- s_high_webcam = gr.Slider(0, 255, 255, step=1, label="S High")
99
- with gr.Column():
100
- v_low_webcam = gr.Slider(0, 255, 0, step=1, label="V Low")
101
- v_high_webcam = gr.Slider(0, 255, 255, step=1, label="V High")
102
-
103
- with gr.Row():
104
- # 顯示結果
105
- webcam_original = gr.Image(label="原始圖像")
106
- webcam_mask = gr.Image(label="遮罩")
107
- webcam_result = gr.Image(label="過濾結果")
108
-
109
- with gr.Tab("圖像上傳"):
110
- with gr.Row():
111
- # 圖像上傳區
112
- upload_input = gr.Image(label="上傳圖像")
113
-
114
- with gr.Row():
115
- # HSV 滑桿控制(用於上傳圖像)
116
- with gr.Column():
117
- h_low_upload = gr.Slider(0, 179, 0, step=1, label="H Low")
118
- h_high_upload = gr.Slider(0, 179, 179, step=1, label="H High")
119
- with gr.Column():
120
- s_low_upload = gr.Slider(0, 255, 0, step=1, label="S Low")
121
- s_high_upload = gr.Slider(0, 255, 255, step=1, label="S High")
122
- with gr.Column():
123
- v_low_upload = gr.Slider(0, 255, 0, step=1, label="V Low")
124
- v_high_upload = gr.Slider(0, 255, 255, step=1, label="V High")
125
 
126
- with gr.Row():
127
- # 顯示結果
128
- upload_original = gr.Image(label="原始圖像")
129
- upload_mask = gr.Image(label="遮罩")
130
- upload_result = gr.Image(label="過濾結果")
131
-
132
- # 處理上傳圖像的按鈕
133
- process_btn = gr.Button("處理圖像")
134
- process_btn.click(
135
- fn=process_image,
136
- inputs=[
137
- upload_input,
138
- h_low_upload, h_high_upload,
139
- s_low_upload, s_high_upload,
140
- v_low_upload, v_high_upload
141
- ],
142
- outputs=[upload_original, upload_mask, upload_result]
143
- )
144
-
145
- # 連接網路攝像頭輸入和滑桿變化到處理函數
146
- webcam_input.change(
147
- fn=process_webcam,
148
- inputs=[
149
- webcam_input,
150
- h_low_webcam, h_high_webcam,
151
- s_low_webcam, s_high_webcam,
152
- v_low_webcam, v_high_webcam
153
- ],
154
- outputs=[webcam_original, webcam_mask, webcam_result]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  )
156
 
157
- # 當滑桿值改變時,重新處理網路攝像頭圖像
158
- h_low_webcam.change(lambda *args: process_webcam(*args),
159
- inputs=[webcam_input, h_low_webcam, h_high_webcam, s_low_webcam, s_high_webcam, v_low_webcam, v_high_webcam],
160
- outputs=[webcam_original, webcam_mask, webcam_result])
161
- h_high_webcam.change(lambda *args: process_webcam(*args),
162
- inputs=[webcam_input, h_low_webcam, h_high_webcam, s_low_webcam, s_high_webcam, v_low_webcam, v_high_webcam],
163
- outputs=[webcam_original, webcam_mask, webcam_result])
164
- s_low_webcam.change(lambda *args: process_webcam(*args),
165
- inputs=[webcam_input, h_low_webcam, h_high_webcam, s_low_webcam, s_high_webcam, v_low_webcam, v_high_webcam],
166
- outputs=[webcam_original, webcam_mask, webcam_result])
167
- s_high_webcam.change(lambda *args: process_webcam(*args),
168
- inputs=[webcam_input, h_low_webcam, h_high_webcam, s_low_webcam, s_high_webcam, v_low_webcam, v_high_webcam],
169
- outputs=[webcam_original, webcam_mask, webcam_result])
170
- v_low_webcam.change(lambda *args: process_webcam(*args),
171
- inputs=[webcam_input, h_low_webcam, h_high_webcam, s_low_webcam, s_high_webcam, v_low_webcam, v_high_webcam],
172
- outputs=[webcam_original, webcam_mask, webcam_result])
173
- v_high_webcam.change(lambda *args: process_webcam(*args),
174
- inputs=[webcam_input, h_low_webcam, h_high_webcam, s_low_webcam, s_high_webcam, v_low_webcam, v_high_webcam],
175
- outputs=[webcam_original, webcam_mask, webcam_result])
176
-
177
- # 當滑桿值改變時,重新處理上傳的圖像
178
- for slider in [h_low_upload, h_high_upload, s_low_upload, s_high_upload, v_low_upload, v_high_upload]:
179
- slider.change(
180
- fn=process_image,
181
- inputs=[
182
- upload_input,
183
- h_low_upload, h_high_upload,
184
- s_low_upload, s_high_upload,
185
- v_low_upload, v_high_upload
186
- ],
187
- outputs=[upload_original, upload_mask, upload_result]
188
- )
 
 
 
 
 
 
 
 
 
 
 
189
 
190
  # 啟動 Gradio 應用
191
  if __name__ == "__main__":
 
2
  import numpy as np
3
  import gradio as gr
4
 
5
+ def hsv_filter(image, h_low=0, h_high=179, s_low=0, s_high=255, v_low=0, v_high=255):
 
 
 
6
  """
7
  對輸入的圖像應用 HSV 過濾
8
 
9
  Args:
10
+ image: 輸入的圖像(來自上傳)
11
  h_low, h_high: Hue(色調)的最低和最高值
12
  s_low, s_high: Saturation(飽和度)的最低和最高值
13
  v_low, v_high: Value(亮度)的最低和最高值
 
16
  原始圖像、HSV 過濾遮罩和過濾後的結果
17
  """
18
  if image is None:
19
+ # 如果沒有圖像,返回None
20
  return None, None, None
21
 
22
+ # 將圖像轉換為BGR(如果它是RGB)
23
+ if len(image.shape) == 3 and image.shape[2] == 3:
24
+ # Gradio 使用 RGB,但 OpenCV 使用 BGR
25
+ image_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
26
+ else:
27
+ image_bgr = image
28
+
29
  # 將圖像轉換為 HSV 色彩空間
30
+ hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
31
 
32
  # 設置 HSV 過濾範圍
33
  lower = np.array([h_low, s_low, v_low])
 
37
  mask = cv2.inRange(hsv, lower, upper)
38
 
39
  # 使用遮罩從原始圖像中提取物體
40
+ result = cv2.bitwise_and(image_bgr, image_bgr, mask=mask)
41
+
42
+ # 將結果轉換回 RGB 以在 Gradio 中顯示
43
+ result_rgb = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
44
 
45
  # 將遮罩轉換為 RGB 以便在 Gradio 中顯示
46
  mask_rgb = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)
47
 
48
+ # 確保原始圖像也是 RGB
49
+ orig_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
50
+
51
+ return orig_rgb, mask_rgb, result_rgb
52
 
53
+ def create_test_image():
54
  """
55
+ 創建一個測試圖像,包含不同顏色區塊,用於演示 HSV 過濾效果
 
 
 
 
 
 
 
56
  """
57
+ # 創建一個白色背景
58
+ test_image = np.ones((300, 400, 3), dtype=np.uint8) * 255
59
+
60
+ # 添加不同顏色的區塊(BGR 格式)
61
+ # 紅色區塊
62
+ test_image[50:150, 50:150] = [0, 0, 255] # BGR格式的紅色
63
+ # 綠色區塊
64
+ test_image[50:150, 200:300] = [0, 255, 0] # BGR格式的綠色
65
+ # 藍色區塊
66
+ test_image[200:250, 50:350] = [255, 0, 0] # BGR格式的藍色
67
+ # 黃色區塊
68
+ test_image[150:200, 150:200] = [0, 255, 255] # BGR格式的黃色
69
+
70
+ # 將BGR轉換為RGB格式
71
+ test_image_rgb = cv2.cvtColor(test_image, cv2.COLOR_BGR2RGB)
72
+
73
+ return test_image_rgb
74
 
75
  def process_image(image, h_low, h_high, s_low, s_high, v_low, v_high):
76
  """
77
+ 處理圖像的主函數
 
 
 
 
 
 
 
78
  """
79
  if image is None:
80
+ # 如果沒有上傳圖像,使用測試圖像
81
+ image = create_test_image()
82
 
83
  return hsv_filter(image, h_low, h_high, s_low, s_high, v_low, v_high)
84
 
85
+ # 創建 Gradio 界面
86
  with gr.Blocks(title="HSV 顏色過濾器") as demo:
87
  gr.Markdown("# HSV 顏色過濾器")
88
+ gr.Markdown("上傳圖像或使用測試圖像,然後調整 HSV 值範圍進行顏色過濾")
89
+
90
+ with gr.Row():
91
+ # 圖像輸入區域
92
+ with gr.Column(scale=1):
93
+ gr.Markdown("### 輸入圖像")
94
+ input_image = gr.Image(type="numpy", label="上傳圖像")
95
+ test_btn = gr.Button("使用測試圖像")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ # HSV 滑桿控制區域
98
+ with gr.Column(scale=1):
99
+ gr.Markdown("### HSV 參數控制")
100
+ with gr.Row():
101
+ with gr.Column():
102
+ h_low = gr.Slider(0, 179, 0, step=1, label="H Low(色調最小值)")
103
+ h_high = gr.Slider(0, 179, 179, step=1, label="H High(色調最大值)")
104
+ with gr.Column():
105
+ s_low = gr.Slider(0, 255, 0, step=1, label="S Low(飽和度最小值)")
106
+ s_high = gr.Slider(0, 255, 255, step=1, label="S High(飽和度最大值)")
107
+ with gr.Column():
108
+ v_low = gr.Slider(0, 255, 0, step=1, label="V Low(亮度最小值)")
109
+ v_high = gr.Slider(0, 255, 255, step=1, label="V High(亮度最大值)")
110
+
111
+ # 創建一些預設值按鈕
112
+ gr.Markdown("### 常用顏色預設")
113
+ with gr.Row():
114
+ red_btn = gr.Button("紅色")
115
+ green_btn = gr.Button("綠色")
116
+ blue_btn = gr.Button("藍色")
117
+ yellow_btn = gr.Button("黃色")
118
+
119
+ # 結果顯示區域
120
+ with gr.Row():
121
+ original_output = gr.Image(type="numpy", label="原始圖像")
122
+ mask_output = gr.Image(type="numpy", label="遮罩")
123
+ result_output = gr.Image(type="numpy", label="過濾結果")
124
+
125
+ # 設置事件處理
126
+ # 測試圖像按鈕
127
+ test_btn.click(
128
+ fn=lambda: create_test_image(),
129
+ inputs=[],
130
+ outputs=[input_image]
131
+ )
132
+
133
+ # 處理圖像函數
134
+ def process_and_update(*args):
135
+ return process_image(*args)
136
+
137
+ # 連接輸入和滑桿到處理函數
138
+ inputs = [input_image, h_low, h_high, s_low, s_high, v_low, v_high]
139
+ outputs = [original_output, mask_output, result_output]
140
+
141
+ # 當圖像或任何滑桿變化時觸發處理函數
142
+ input_image.change(process_and_update, inputs=inputs, outputs=outputs)
143
+
144
+ for slider in [h_low, h_high, s_low, s_high, v_low, v_high]:
145
+ slider.change(process_and_update, inputs=inputs, outputs=outputs)
146
+
147
+ # 預設值按鈕
148
+ # 紅色 (Hue: ~0-10 或 ~160-179)
149
+ red_btn.click(
150
+ fn=lambda: [None, 0, 10, 100, 255, 100, 255],
151
+ inputs=[],
152
+ outputs=[input_image, h_low, h_high, s_low, s_high, v_low, v_high]
153
+ ).then(
154
+ fn=process_and_update,
155
+ inputs=inputs,
156
+ outputs=outputs
157
  )
158
 
159
+ # 綠色 (Hue: ~35-85)
160
+ green_btn.click(
161
+ fn=lambda: [None, 35, 85, 100, 255, 100, 255],
162
+ inputs=[],
163
+ outputs=[input_image, h_low, h_high, s_low, s_high, v_low, v_high]
164
+ ).then(
165
+ fn=process_and_update,
166
+ inputs=inputs,
167
+ outputs=outputs
168
+ )
169
+
170
+ # 藍色 (Hue: ~90-130)
171
+ blue_btn.click(
172
+ fn=lambda: [None, 90, 130, 100, 255, 100, 255],
173
+ inputs=[],
174
+ outputs=[input_image, h_low, h_high, s_low, s_high, v_low, v_high]
175
+ ).then(
176
+ fn=process_and_update,
177
+ inputs=inputs,
178
+ outputs=outputs
179
+ )
180
+
181
+ # 黃色 (Hue: ~20-35)
182
+ yellow_btn.click(
183
+ fn=lambda: [None, 20, 35, 100, 255, 100, 255],
184
+ inputs=[],
185
+ outputs=[input_image, h_low, h_high, s_low, s_high, v_low, v_high]
186
+ ).then(
187
+ fn=process_and_update,
188
+ inputs=inputs,
189
+ outputs=outputs
190
+ )
191
+
192
+ # 初始加載時自動生成測試圖像
193
+ demo.load(
194
+ fn=lambda: [create_test_image()],
195
+ inputs=None,
196
+ outputs=[input_image]
197
+ ).then(
198
+ fn=process_and_update,
199
+ inputs=inputs,
200
+ outputs=outputs
201
+ )
202
 
203
  # 啟動 Gradio 應用
204
  if __name__ == "__main__":