Add results page with functionality

This commit is contained in:
Piotr Szkudlarek 2023-12-23 17:01:39 +01:00
parent a75c94d5c6
commit 270bb92c4c
11 changed files with 103 additions and 32 deletions

View File

@ -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,
),
]

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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%}

View File

@ -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}}