Add results page with functionality
This commit is contained in:
parent
a75c94d5c6
commit
270bb92c4c
@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 4.2.7 on 2023-12-19 21:15
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("DetectionApp", "0010_rename_detectimage_uploadimage"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="predictedimage",
|
||||||
|
name="class_name",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="predictedimage",
|
||||||
|
name="confidence",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="predictedimage",
|
||||||
|
name="prediction_data",
|
||||||
|
field=models.JSONField(default={"data": "no predictions"}),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.core.validators import FileExtensionValidator
|
from django.core.validators import FileExtensionValidator
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -17,8 +18,7 @@ class UploadImage(models.Model):
|
|||||||
class PredictedImage(models.Model):
|
class PredictedImage(models.Model):
|
||||||
original_image = models.OneToOneField(UploadImage, on_delete=models.CASCADE)
|
original_image = models.OneToOneField(UploadImage, on_delete=models.CASCADE)
|
||||||
image = models.ImageField(upload_to=f"plankton/%Y/%m/%d/{original_image.name}")
|
image = models.ImageField(upload_to=f"plankton/%Y/%m/%d/{original_image.name}")
|
||||||
confidence = models.FloatField()
|
prediction_data = models.JSONField()
|
||||||
class_name = models.CharField(max_length=100)
|
|
||||||
date_predicted = models.DateTimeField(auto_now_add=True)
|
date_predicted = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -28,3 +28,9 @@ class PredictedImage(models.Model):
|
|||||||
@property
|
@property
|
||||||
def get_original_image(self):
|
def get_original_image(self):
|
||||||
return self.original_image.image
|
return self.original_image.image
|
||||||
|
|
||||||
|
def get_prediction_data(self):
|
||||||
|
results = json.loads(self.prediction_data)
|
||||||
|
for pred in results:
|
||||||
|
pred["confidence"] = round(pred["confidence"] * 100, 2)
|
||||||
|
return results
|
||||||
|
@ -16,5 +16,6 @@ def predict_image(image):
|
|||||||
name=f"{image.image.name}_predicted",
|
name=f"{image.image.name}_predicted",
|
||||||
imgsz=[640, 640],
|
imgsz=[640, 640],
|
||||||
)
|
)
|
||||||
x = json.loads(results[0].tojson())
|
for r in results:
|
||||||
|
x = r.tojson()
|
||||||
return x
|
return x
|
||||||
|
@ -9,6 +9,7 @@ from django.utils.decorators import method_decorator
|
|||||||
from .models import UploadImage, PredictedImage
|
from .models import UploadImage, PredictedImage
|
||||||
from .utils import predict_image
|
from .utils import predict_image
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
class DetectView(View):
|
class DetectView(View):
|
||||||
@ -37,22 +38,20 @@ class DetectView(View):
|
|||||||
)
|
)
|
||||||
image.save()
|
image.save()
|
||||||
try:
|
try:
|
||||||
results_metrics = prediciton_results[0]
|
results_metrics = prediciton_results
|
||||||
except IndexError as e:
|
except IndexError as e:
|
||||||
PredictedImage.objects.create(
|
predicted_image = PredictedImage.objects.create(
|
||||||
original_image=image,
|
original_image=image,
|
||||||
image=image.predicted_image_url,
|
image=image.predicted_image_url,
|
||||||
confidence=0.0,
|
prediction_data={"data": "no results"},
|
||||||
class_name="no predictions",
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
PredictedImage.objects.create(
|
predicted_image = PredictedImage.objects.create(
|
||||||
original_image=image,
|
original_image=image,
|
||||||
image=image.predicted_image_url,
|
image=image.predicted_image_url,
|
||||||
confidence=results_metrics["confidence"],
|
prediction_data=results_metrics,
|
||||||
class_name=results_metrics["name"],
|
|
||||||
)
|
)
|
||||||
predictions.append(image)
|
predictions.append(predicted_image)
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"results.html",
|
"results.html",
|
||||||
|
Binary file not shown.
@ -1,10 +1,12 @@
|
|||||||
body, html{
|
body, html{
|
||||||
height:100%;
|
height:100%;
|
||||||
margin: 0px 0px 0px 0px;
|
min-height: 100%;
|
||||||
|
margin: 35px 0px 0px 0px;
|
||||||
display:flex;
|
display:flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
font-family:'Inter', sans-serif;
|
font-family:'Inter', sans-serif;
|
||||||
|
overflow-x:hidden
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-menu a{
|
.top-menu a{
|
||||||
@ -16,10 +18,12 @@ body, html{
|
|||||||
.top-menu{
|
.top-menu{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
position: fixed;
|
||||||
|
top:0;
|
||||||
|
width: 100%;
|
||||||
justify-content:flex-end;
|
justify-content:flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color:lightgray;
|
background-color:lightgray;
|
||||||
margin-bottom:5px;
|
|
||||||
height: 45px;
|
height: 45px;
|
||||||
border: grey solid;
|
border: grey solid;
|
||||||
border-width: 0px 2px 2px 2px;
|
border-width: 0px 2px 2px 2px;
|
||||||
@ -29,14 +33,10 @@ body, html{
|
|||||||
|
|
||||||
.footer{
|
.footer{
|
||||||
display:flex;
|
display:flex;
|
||||||
position:fixed;
|
position:relative;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
width: 100%;
|
||||||
left:0;
|
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 5px;
|
|
||||||
background-color: lightgray;
|
background-color: lightgray;
|
||||||
border: grey solid;
|
border: grey solid;
|
||||||
border-width: 2px 2px 0px 2px;
|
border-width: 2px 2px 0px 2px;
|
||||||
|
@ -5,29 +5,31 @@ form{
|
|||||||
display:flex;
|
display:flex;
|
||||||
flex-direction:row;
|
flex-direction:row;
|
||||||
margin:auto;
|
margin:auto;
|
||||||
|
overflow:hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.side_menu{
|
.side_menu{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: space-between;
|
||||||
align-items:center;
|
align-items:center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 25%;
|
width: 25%;
|
||||||
background-color: lightgray;
|
background-color: lightgray;
|
||||||
border: grey solid;
|
border: 2px grey solid;
|
||||||
border-width: 2px;
|
padding: 0px 0px 40px 0px;
|
||||||
margin-bottom: 59px;
|
margin-bottom: 5px;
|
||||||
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#description{
|
#description{
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin: 10px 0px 15px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#submit{
|
#submit{
|
||||||
margin-bottom: 40px;
|
|
||||||
background-color: chartreuse;
|
background-color: chartreuse;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
@ -62,3 +64,24 @@ form{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.image_number {
|
||||||
|
font-size: medium;
|
||||||
|
margin: 0 0 5px 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: white;
|
||||||
|
width: 70%;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px black solid;
|
||||||
|
border-radius: 5%;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detection_info{
|
||||||
|
font-size: large;
|
||||||
|
text-decoration:solid;
|
||||||
|
color: black;
|
||||||
|
}
|
@ -5,6 +5,7 @@ form{
|
|||||||
display:flex;
|
display:flex;
|
||||||
flex-direction:row;
|
flex-direction:row;
|
||||||
margin:auto;
|
margin:auto;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ form{
|
|||||||
background-color: lightgray;
|
background-color: lightgray;
|
||||||
border: grey solid;
|
border: grey solid;
|
||||||
border-width: 2px;
|
border-width: 2px;
|
||||||
margin-bottom: 59px;
|
margin-bottom:5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<title>Plankton Detector</title>
|
<title>Plankton Detector</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="top-menu">
|
<div class="top-menu" id="top-menu">
|
||||||
<a href="{% url 'posts' %}">Community</a>
|
<a href="{% url 'posts' %}">Community</a>
|
||||||
<a href="{% url 'detect' %}">Predict</a>
|
<a href="{% url 'detect' %}">Predict</a>
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
@ -24,17 +24,17 @@
|
|||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
{%block content%}{%endblock content%}
|
{%block content%}{%endblock content%}
|
||||||
<div class="footer">
|
<footer class="footer">
|
||||||
<p>Footer</p>
|
<p>Footer</p>
|
||||||
</div>
|
</footer>
|
||||||
<script>
|
<script>
|
||||||
var prevScrollpos = window.pageYOffset;
|
var prevScrollpos = window.pageYOffset;
|
||||||
window.onscroll = function() {
|
window.onscroll = function() {
|
||||||
var currentScrollPos = window.pageYOffset;
|
var currentScrollPos = window.pageYOffset;
|
||||||
if (prevScrollpos > currentScrollPos) {
|
if (prevScrollpos > currentScrollPos) {
|
||||||
document.getElementsByClassName("top-menu").style.top = "0";
|
document.getElementById("top-menu").style.top = "0";
|
||||||
} else {
|
} else {
|
||||||
document.getElementsByClassName("top-menu").style.top = "-50px";
|
document.getElementById("top-menu").style.top = "-45px";
|
||||||
}
|
}
|
||||||
prevScrollpos = currentScrollPos;
|
prevScrollpos = currentScrollPos;
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,29 @@
|
|||||||
<button onclick="location.href='{% url 'login' %}'" id='submit' method="GET" type='button'>Login</button>
|
<button onclick="location.href='{% url 'login' %}'" id='submit' method="GET" type='button'>Login</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p id="description">Results:</p>
|
<p id="description">Results:</p>
|
||||||
|
{%for img in img_url%}
|
||||||
|
<p class="image_number">Image {{forloop.counter}}</p>
|
||||||
|
{%for detection in img.get_prediction_data%}
|
||||||
|
<div class="results">
|
||||||
|
<p class="detection_info">{{detection.name}}: {{detection.confidence}}%</p>
|
||||||
|
</div>
|
||||||
|
{%endfor%}
|
||||||
|
{%endfor%}
|
||||||
<button onclick="location.href='{% url 'detect' %}'" id='submit' method="GET" type='button'>Submit again</button>
|
<button onclick="location.href='{% url 'detect' %}'" id='submit' method="GET" type='button'>Submit again</button>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
<div class="upload_field">
|
<div class="upload_field">
|
||||||
<label>
|
<label>
|
||||||
{%for img in img_url%}
|
{%for img in img_url%}
|
||||||
<img src="{%get_media_prefix%}{{img.predicted_image_url}}" alt="upload_image" style="width:640px; height:460px;">
|
<img src="{{img.image.url}}" alt="upload_image" style="width:640px; height:460px;">
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<script>
|
||||||
|
var results=document.getElementsByClassName("results")
|
||||||
|
for (var i = 0; i < results.length; i++){
|
||||||
|
results[i].style.background=`linear-gradient(90deg, #7fff00 ${results[i].textContent.split(":")[1]}, #FFFFFF 0%)`
|
||||||
|
};
|
||||||
|
</script>
|
||||||
{%endblock content%}
|
{%endblock content%}
|
@ -4,7 +4,7 @@
|
|||||||
<link rel="stylesheet" href="{%static 'DetectionApp/css/upload.css' %}">
|
<link rel="stylesheet" href="{%static 'DetectionApp/css/upload.css' %}">
|
||||||
{%endblock extracss%}
|
{%endblock extracss%}
|
||||||
{%block content%}
|
{%block content%}
|
||||||
<form method="POST" enctype="multipart/form-data">
|
<form method="POST" enctype="multipart/form-data" id="upload_form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="side_menu">
|
<div class="side_menu">
|
||||||
{% if not user.is_authenticated %}
|
{% if not user.is_authenticated %}
|
||||||
@ -15,6 +15,7 @@
|
|||||||
<input type="submit" id="submit" value="Submit">
|
<input type="submit" id="submit" value="Submit">
|
||||||
{%endif%}
|
{%endif%}
|
||||||
</div>
|
</div>
|
||||||
|
<div id="progress"></div>
|
||||||
<div class="upload_field">
|
<div class="upload_field">
|
||||||
<label for="id_image", class="upload_button" id="image-preview-container">
|
<label for="id_image", class="upload_button" id="image-preview-container">
|
||||||
{{form.as_p}}
|
{{form.as_p}}
|
||||||
|
Loading…
Reference in New Issue
Block a user