changed website structure, added new cnn files

This commit is contained in:
2026-05-06 16:01:10 +02:00
parent ad5acf85f9
commit 17d0147173
5 changed files with 225 additions and 23 deletions
+51
View File
@@ -0,0 +1,51 @@
import torch
import torch.nn as nn
import torchvision
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, random_split
import matplotlib.pyplot as plt
from bird_cnn import Bird_CNN, sample, trainCNN
from enum import Enum
from PIL import Image
SAVE_PATH = "./saved_models"
IMAGE_SIZE = 64
class bird_species(Enum):
Common_Kingfisher = 0
CommonMyna = 1
House_Crow = 2
Indian_Peacock = 3
Indian_Pitta = 4
Ruddy_Shelduck = 5
Sarus_Crane = 6
transform = transforms.Compose([
transforms.Resize(IMAGE_SIZE),
transforms.CenterCrop(IMAGE_SIZE),
transforms.ToTensor()
])
dataset = datasets.ImageFolder("data/train", transform=transform)
train_size = int(0.8 * len(dataset))
val_size = len(dataset) - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)
device = torch.device("cpu") if not torch.cuda.is_available() else torch.device("cuda:0")
print("Using device", device)
model = Bird_CNN(c_in=3, c_hidden=32, c_out=7)
model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3, weight_decay=1e-4)
loss_module = nn.CrossEntropyLoss()
trainCNN(model, optimizer, loss_module, train_loader, val_loader, device, 50, SAVE_PATH=SAVE_PATH, save=True)
+85
View File
@@ -0,0 +1,85 @@
from collections import defaultdict
from enum import Enum
import os
import numpy as np
import matplotlib.pyplot as plt
import cv2
import torch
from torchvision import transforms
import torch.nn.functional as F
from bird_cnn import Bird_CNN
from PIL import Image
BUILD_PATH = "./build_models"
IMAGE_SIZE = 64
class bird_species(Enum):
Common_Kingfisher = 0
CommonMyna = 1
House_Crow = 2
Indian_Peacock = 3
Indian_Pitta = 4
Ruddy_Shelduck = 5
Sarus_Crane = 6
transform = transforms.Compose([
transforms.Resize(IMAGE_SIZE),
transforms.CenterCrop(IMAGE_SIZE),
transforms.ToTensor()
])
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = Bird_CNN(c_in=3, c_hidden=16, c_out=7)
full_path = os.path.join(BUILD_PATH, "bird_cnn")
model.load_state_dict(torch.load(full_path, map_location=torch.device(device)))
model.to(device)
model.eval()
img = cv2.imread("./testimages/two_crows.jpg")
if img is None:
raise ValueError("Image not found or path is wrong")
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
ss.setBaseImage(img)
ss.switchToSelectiveSearchFast()
rects = ss.process()
# convert to array for easy sorting
rects = np.array(rects)
# compute area
areas = rects[:, 2] * rects[:, 3]
# sort by area (descending)
idx = np.argsort(-areas)
# take top 10
top10 = rects[idx[:200]]
class_conf_sum = defaultdict(float)
for (x, y, w, h) in top10:
#cv2.rectangle(img_copy, (x, y), (x + w, y + h), (0, 255, 0), 1)
crop = img[y:y+h, x:x+w]
crop_pil = Image.fromarray(cv2.cvtColor(crop, cv2.COLOR_BGR2RGB))
image = transform(crop_pil).unsqueeze(0).to(device)
with torch.no_grad():
pred = model(image)
probs = F.softmax(pred, dim=1)
confidence, cls = torch.max(probs, dim=1)
if confidence.item() < 0.7:
continue
class_conf_sum[cls.item()] += confidence.item()
for i in range(6):
print(str(i) + ": " + str(class_conf_sum[i]))
Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+77 -10
View File
@@ -1,3 +1,7 @@
.button-div {
height: 40px;
}
.custom-button { .custom-button {
font-size: 1rem; font-size: 1rem;
font-weight: bold; font-weight: bold;
@@ -27,11 +31,10 @@
} }
#site-headline { #site-headline {
margin-left: 100px; margin: 50px min(100px, 10vw) 50px min(100px, 10vw);
margin-bottom: 50px;
color: rgb(47, 168, 208); color: rgb(47, 168, 208);
font-weight: bold; font-weight: bold;
font-size: 4rem; font-size: clamp(1rem, 8vw, 4rem);
position: relative; position: relative;
width: fit-content; width: fit-content;
} }
@@ -67,12 +70,13 @@ a:hover {
flex-wrap: wrap; flex-wrap: wrap;
overflow: hidden; overflow: hidden;
border-radius: 12px; border-radius: 12px;
margin: 180px 50px 50px 50px; margin: 50px 50px 50px 50px;
} }
.image-box { .image-box {
height: 400px; height: fit-content;
margin-top: 40px; margin-top: 40px;
margin-bottom: 40px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -86,7 +90,10 @@ a:hover {
cursor: pointer; cursor: pointer;
border: 2px solid black; border: 2px solid black;
border-Radius: 10px; border-Radius: 10px;
user-select: none;
height: auto;
max-height: 400px;
max-width: min(700px, 80vw);
} }
.image-box img:hover { .image-box img:hover {
@@ -95,15 +102,27 @@ a:hover {
.content-block { .content-block {
display: flex; display: flex;
justify-content: center;
align-items: center; align-items: center;
gap: 20px; flex-wrap: wrap;
height: 40px; column-gap: 20px;
height: fit-content;
width: fit-content;
}
.loader-container {
scroll-margin-top: 100px;
width: 85px;
height: 35px;
display: flex;
justify-content: center;
padding: 20px 0px 20px 0px;
} }
/* HTML: <div class="loader"></div> */ /* HTML: <div class="loader"></div> */
.loader { .loader {
width: 85px; width: 100%;
height: 25px; height: 100%;
--g1: conic-gradient(from 90deg at left 3px top 3px, #0000 90deg, #fff 0); --g1: conic-gradient(from 90deg at left 3px top 3px, #0000 90deg, #fff 0);
--g2: conic-gradient(from -90deg at bottom 3px right 3px, #0000 90deg, #fff 0); --g2: conic-gradient(from -90deg at bottom 3px right 3px, #0000 90deg, #fff 0);
background: var(--g1), var(--g1), var(--g1), var(--g2), var(--g2), var(--g2); background: var(--g1), var(--g1), var(--g1), var(--g2), var(--g2), var(--g2);
@@ -136,4 +155,52 @@ a:hover {
100% { 100% {
background-size: 25px 100%, 25px 100%, 25px 100% background-size: 25px 100%, 25px 100%, 25px 100%
} }
}
.site-box {
margin-top: 150px;
width: 100%;
}
.request-box {
height: fit-content;
width: min(700px, 80%);
display: flex;
flex-direction: column;
align-items: center;
flex: 0 0 auto;
margin: 0px 50px 0px 50px;
}
.request-box * {
box-sizing: content-box;
}
.input-box {
scroll-margin-top: 100px;
width: min(500px, 100%);
height: 160px;
display: flex;
justify-content: space-evenly;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.response-block {
width: 80%;
height: 100px;
margin: 40px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 40px;
}
.conten-block-text {
display: flex;
flex-direction: column;
justify-content: center;
margin: 0;
} }
+12 -13
View File
@@ -85,7 +85,7 @@ function Bird_CNN() {
return ( return (
<> <>
<div className='site-box' style={{ marginTop: "150px" }}> <div className='site-box'>
<h1 id='site-headline'>Bird Species Expert</h1> <h1 id='site-headline'>Bird Species Expert</h1>
<div className='content-box' style={{ display: "flex", flexWrap: "wrap", justifyContent: "center" }}> <div className='content-box' style={{ display: "flex", flexWrap: "wrap", justifyContent: "center" }}>
<div className='explanation-box left'> <div className='explanation-box left'>
@@ -93,15 +93,15 @@ function Bird_CNN() {
<span>Select an image and upload it to our bird expert. You will receive a classification and how certain the expert is with her opinion. Be aware that the expert may not be always right.</span> <span>Select an image and upload it to our bird expert. You will receive a classification and how certain the expert is with her opinion. Be aware that the expert may not be always right.</span>
</div> </div>
<div className='request-box' style={{ height: "800px", width: "700px", display: "flex", flexDirection: "column", alignItems: "center", flex: "0 0 auto", margin: "100px 50px 0px 50px" }}> <div className='request-box'>
<div ref={scrollRefUploadButton} className='input-box' style={{ scrollMarginTop: "100px", marginBottom: "80px", width: "500px", height: "40px", display: "flex", justifyContent: "space-evenly", alignItems: "center" }}> <div ref={scrollRefUploadButton} className='input-box'>
<div> <div className='button-div'>
<input disabled={loading} ref={fileInputRef} type="file" id='fileUpload' accept="image/jpeg" onChange={handleImage} style={{ display: "none" }} /> <input disabled={loading} ref={fileInputRef} type="file" id='fileUpload' accept="image/jpeg" onChange={handleImage} style={{ display: "none" }} />
<label htmlFor="fileUpload" className="custom-button"> <label htmlFor="fileUpload" className="custom-button">
Select Image Select Image
</label> </label>
</div> </div>
<div> <div className='button-div'>
<button id='button-send' onClick={sendImage} style={{ display: "none" }} disabled={loading} /> <button id='button-send' onClick={sendImage} style={{ display: "none" }} disabled={loading} />
<label htmlFor="button-send" className="custom-button inactive" ref={uploadButton}> <label htmlFor="button-send" className="custom-button inactive" ref={uploadButton}>
Ask Expert Ask Expert
@@ -116,25 +116,24 @@ function Bird_CNN() {
disabled={loading} disabled={loading}
src={preview} src={preview}
alt="preview" alt="preview"
style={{ height: "100%", userSelect: "none", maxWidth: "700px" }}
/> />
</div> </div>
<div ref={scrollRefClassifiction} style={{ scrollMarginTop: "100px", paddingTop: "10px", marginTop: "30px", width: "85px", height: "35px", display: "flex", justifyContent: "center", minHeight: "25px", minWidth: "85px" }}> <div ref={scrollRefClassifiction} className='loader-container'>
{loading && <div className='loader'></div>} {loading && <div className='loader'></div>}
</div> </div>
<div className='response-block' style={{ marginTop: "40px", width: "80%", margin: "40px", display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "10px" }}> <div className='response-block'>
<div className='content-block class'> <div className='content-block class'>
<h3>Bird Species: </h3> <h3 className='conten-block-text'>Bird Species: </h3>
<p id='bird-class-text'>{birdClass}</p> <p id='bird-class-text' className='conten-block-text'>{birdClass}</p>
</div> </div>
<div className='content-block confidence'> <div className='content-block confidence'>
<h4>Model Confidence: </h4> <h4 className='conten-block-text'>Model Confidence: </h4>
<p id='bird-confidence-text'>{confidence}</p> <p id='bird-confidence-text' className='conten-block-text'>{confidence}</p>
</div> </div>
{error && <h4>An Error has uccured. Please try again later.</h4>} {error && <h4 className='conten-block-text'>An Error has uccured. Please try again later.</h4>}
</div> </div>
</div> </div>