import gradio as gr
import json
import os
import torch
from torchvision import transforms
from PIL import Image
import folium
import base64
import glob
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)
# JSON 파일에서 새 데이터 로드
with open('DB/bird_data.json', 'r', encoding='utf-8') as f:
bird_data = json.load(f)
# 이미지 경로 설정
image_folder = 'DB/bird_image'
model_ft = torch.load('bird_detection_model.pth', map_location=torch.device('cpu'))
model_ft.eval()
# 새의 클래스 이름 로드
with open('DB/class_names.json', 'r', encoding='utf-8') as f:
classes = json.load(f)
# 대전과학고 위치 설정
daejeon_science_high_location = [36.373719, 127.370415]
def create_image_popup(image_path):
try:
with open(image_path, 'rb') as image_file:
encoded = base64.b64encode(image_file.read()).decode()
return f'
'
except:
return ''
def create_map():
m = folium.Map(location=daejeon_science_high_location, zoom_start=15)
# 대전과학고 마커 추가
folium.Marker(
daejeon_science_high_location,
popup="대전과학고등학교",
tooltip="대전과학고등학교"
).add_to(m)
# bird_locations_json 폴더의 모든 JSON 파일 처리
location_files = glob.glob('./DB/bird_locations_json/bird_locations_*.json')
for file_path in location_files:
# 새 이름 추출 (파일명에서)
bird_name = file_path.split('_')[-1].replace('.json', '')
print(f"bird_name: {bird_name}")
with open(file_path, 'r', encoding='utf-8') as f:
locations_data = json.load(f)
if bird_name in locations_data and locations_data[bird_name] is not None:
for location_info in locations_data[bird_name]:
latitude = location_info['latitude']
longitude = location_info['longitude']
location = location_info['location']
image_filename = location_info['image_filename']
if location.startswith(' '):
location = location[1:]
# 주소를 좌표로 변환
coordinates = [latitude, longitude]
if coordinates:
# 이미지 경로 생성
image_path = os.path.join('./DB/naturing_bird_image', bird_name, image_filename)
# 팝업 내용 생성
popup_content = f"""
{bird_name}
{location}
{create_image_popup(image_path)}
"""
# 마커 추가
folium.CircleMarker(
location=coordinates,
radius=4,
popup=folium.Popup(popup_content, max_width=300),
tooltip=bird_name,
color='red',
fill=True
).add_to(m)
else:
print(f'{bird_name} 없음')
return m._repr_html_()
def search_birds(search_term):
filtered_gallery = []
for bird_id, bird_info in bird_data.items():
if search_term.lower() in bird_info['common_name'].lower() or search_term.lower() in bird_info['scientific_name'].lower():
image_path = os.path.join(image_folder, f"{bird_id}.jpg")
filtered_gallery.append((image_path, f"{bird_info['common_name']}"))
return filtered_gallery
def main_page():
gallery = []
for bird_id, bird_info in bird_data.items():
image_path = os.path.join(image_folder, f"{bird_id}.jpg")
gallery.append((image_path, f"{bird_info['common_name']}"))
return gallery
def detail_page(evt: gr.SelectData):
image_path = evt.value['image']['path']
bird_id = os.path.basename(image_path).split('.')[0]
selected_bird = bird_data[bird_id]
info = f"""
# {selected_bird['common_name']} ({selected_bird['scientific_name']})
## 분류
- 문: {selected_bird['classification']['phylum']}
- 강: {selected_bird['classification']['class']}
- 목: {selected_bird['classification']['order']}
- 과: {selected_bird['classification']['family']}
- 속: {selected_bird['classification']['genus']}
## 생태적 특징
{selected_bird['ecological_characteristics']}
## 일반적 특징
{selected_bird['general_characteristics']}
"""
return image_path, info
def apply_test_transforms(inp):
out = transforms.functional.resize(inp, [224,224])
out = transforms.functional.to_tensor(out)
out = transforms.functional.normalize(out, [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
return out
def predict(model, filepath):
im = Image.open(filepath)
im_as_tensor = apply_test_transforms(im)
minibatch = torch.stack([im_as_tensor])
if torch.cuda.is_available():
minibatch = minibatch.cuda()
pred = model(minibatch)
_, classnum = torch.max(pred, 1)
print(classnum)
return classes[str(classnum.item())]
def classify_bird(image):
result = predict(model_ft, image)
return result
with gr.Blocks() as demo:
gr.Markdown("# BIORD")
gr.Markdown("## Bird's Information & Organized Regional Database")
# 대전과학고 지도 탭
with gr.Tab("대전과고 지도"):
map_html = gr.HTML(value=create_map())
# 조류 도감 탭
with gr.Tab("조류 도감"):
with gr.Row():
search_input = gr.Textbox(label="새 이름 검색", placeholder="검색하고 싶은 새의 이름을 입력하세요")
with gr.Row():
with gr.Column(scale=2):
gallery = gr.Gallery(value=main_page(), columns=40, rows=6, height=660)
with gr.Column(scale=3):
selected_image = gr.Image(label="선택한 새")
info = gr.Markdown(label="상세 정보")
search_input.change(search_birds, inputs=[search_input], outputs=[gallery])
gallery.select(detail_page, None, [selected_image, info])
# 조류 동정 탭
with gr.Tab("조류 동정"):
image_input = gr.Image(type="filepath")
classify_btn = gr.Button("예측하기")
output = gr.Textbox(label="예측 결과")
classify_btn.click(fn=classify_bird, inputs=image_input, outputs=output)
# 애플리케이션 실행
demo.launch()