diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 35bc3cfec..000000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -app/export.pkl diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..0e40fe8f5 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ + +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/fastai-v3.iml b/.idea/fastai-v3.iml new file mode 100644 index 000000000..62e1c094a --- /dev/null +++ b/.idea/fastai-v3.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/libraries/R_User_Library.xml b/.idea/libraries/R_User_Library.xml new file mode 100644 index 000000000..71f5ff749 --- /dev/null +++ b/.idea/libraries/R_User_Library.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..b69f0de07 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..c33be9dfa --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..94a25f7f4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index c31867fc8..8b1378917 100644 --- a/README.md +++ b/README.md @@ -1,15 +1 @@ -# Starter for deploying [fast.ai](https://www.fast.ai) models on [Render](https://render.com) -This repo can be used as a starting point to deploy [fast.ai](https://github.com/fastai/fastai) models on Render. - -The sample app described here is up at https://fastai-v3.onrender.com. Test it out with bear images! - -You can test your changes locally by installing Docker and using the following command: - -``` -docker build -t fastai-v3 . && docker run --rm -it -p 5000:5000 fastai-v3 -``` - -The guide for production deployment to Render is at https://course.fast.ai/deployment_render.html. - -Please use [Render's fast.ai forum thread](https://forums.fast.ai/t/deployment-platform-render/33953) for questions and support. diff --git a/app/models/export.pkl b/app/models/export.pkl new file mode 100644 index 000000000..8976bf422 Binary files /dev/null and b/app/models/export.pkl differ diff --git a/app/models/model.sav b/app/models/model.sav new file mode 100644 index 000000000..66edd8ab2 Binary files /dev/null and b/app/models/model.sav differ diff --git a/app/server.py b/app/server.py index fc713eaba..27db29cf8 100644 --- a/app/server.py +++ b/app/server.py @@ -1,27 +1,60 @@ import aiohttp import asyncio import uvicorn -from fastai import * from fastai.vision import * from io import BytesIO from starlette.applications import Starlette from starlette.middleware.cors import CORSMiddleware from starlette.responses import HTMLResponse, JSONResponse from starlette.staticfiles import StaticFiles +from PIL import Image as IM -export_file_url = 'https://www.dropbox.com/s/6bgq8t6yextloqp/export.pkl?raw=1' +##rollback +##try +export_file_url = 'https://drive.google.com/uc?export=download&id=1QVxKqLSZwYS42hEoVYztp1awvZX44ppC' #https://drive.google.com/u/0/uc?export=download&confirm=W7Y1&id=1BSva5kuYeZVnsE8M_kwO0QSILdFIgbQC export_file_name = 'export.pkl' +export_file_name_2 = 'model.sav' -classes = ['black', 'grizzly', 'teddys'] +classes = ['NORMAL', 'PNEUMONIA'] + +""" +['AFRICAN FIREFINCH', 'ALBATROSS', 'ALEXANDRINE PARAKEET', 'AMERICAN AVOCET', 'AMERICAN BITTERN', 'AMERICAN COOT', 'AMERICAN GOLDFINCH', + 'AMERICAN KESTREL', 'AMERICAN PIPIT', 'AMERICAN REDSTART', 'ANHINGA', 'ANNAS HUMMINGBIRD', 'ANTBIRD', 'ARARIPE MANAKIN', 'ASIAN CRESTED IBIS', + 'BALD EAGLE', 'BALI STARLING', 'BALTIMORE ORIOLE', 'BANANAQUIT', 'BAR-TAILED GODWIT', 'BARN OWL', 'BARN SWALLOW', 'BARRED PUFFBIRD', + 'BAY-BREASTED WARBLER', 'BEARDED BARBET', 'BELTED KINGFISHER', 'BIRD OF PARADISE', 'BLACK FRANCOLIN', 'BLACK SKIMMER', 'BLACK SWAN', + 'BLACK THROATED WARBLER', 'BLACK VULTURE', 'BLACK-CAPPED CHICKADEE', 'BLACK-NECKED GREBE', 'BLACK-THROATED SPARROW', 'BLACKBURNIAM WARBLER', + 'BLUE GROUSE', 'BLUE HERON', 'BOBOLINK', 'BROWN NOODY', 'BROWN THRASHER', 'CACTUS WREN', 'CALIFORNIA CONDOR', 'CALIFORNIA GULL', 'CALIFORNIA QUAIL', + 'CANARY', 'CAPE MAY WARBLER', 'CAPUCHINBIRD', 'CARMINE BEE-EATER', 'CASPIAN TERN', 'CASSOWARY', 'CHARA DE COLLAR', 'CHIPPING SPARROW', 'CHUKAR PARTRIDGE', + 'CINNAMON TEAL', 'COCK OF THE ROCK', 'COCKATOO', 'COMMON GRACKLE', 'COMMON HOUSE MARTIN', 'COMMON LOON', 'COMMON POORWILL', 'COMMON STARLING', + 'COUCHS KINGBIRD', 'CRESTED AUKLET', 'CRESTED CARACARA', 'CROW', 'CROWNED PIGEON', 'CUBAN TODY', 'CURL CRESTED ARACURI', 'D-ARNAUDS BARBET', + 'DARK EYED JUNCO', 'DOWNY WOODPECKER', 'EASTERN BLUEBIRD', 'EASTERN MEADOWLARK', 'EASTERN ROSELLA', 'EASTERN TOWEE', 'ELEGANT TROGON', + 'ELLIOTS PHEASANT', 'EMPEROR PENGUIN', 'EMU', 'EURASIAN MAGPIE', 'EVENING GROSBEAK', 'FLAME TANAGER', 'FLAMINGO', 'FRIGATE', 'GAMBELS QUAIL', + 'GILA WOODPECKER', 'GILDED FLICKER', 'GLOSSY IBIS', 'GOLD WING WARBLER', 'GOLDEN CHEEKED WARBLER', 'GOLDEN CHLOROPHONIA', 'GOLDEN EAGLE', + 'GOLDEN PHEASANT', 'GOLDEN PIPIT', 'GOULDIAN FINCH', 'GRAY CATBIRD', 'GRAY PARTRIDGE', 'GREEN JAY', 'GREY PLOVER', 'GUINEAFOWL', 'GYRFALCON', + 'HARPY EAGLE', 'HAWAIIAN GOOSE', 'HOODED MERGANSER', 'HOOPOES', 'HORNBILL', 'HORNED GUAN', 'HORNED SUNGEM', 'HOUSE FINCH', 'HOUSE SPARROW', + 'IMPERIAL SHAQ', 'INCA TERN', 'INDIAN BUSTARD', 'INDIGO BUNTING', 'JABIRU', 'JAVAN MAGPIE', 'KAKAPO', 'KILLDEAR', 'KING VULTURE', 'KIWI', + 'KOOKABURRA', 'LARK BUNTING', 'LEARS MACAW', 'LILAC ROLLER', 'LONG-EARED OWL', 'MALABAR HORNBILL', 'MALACHITE KINGFISHER', 'MALEO', 'MALLARD DUCK', + 'MANDRIN DUCK', 'MARABOU STORK', 'MASKED BOOBY', 'MIKADO PHEASANT', 'MOURNING DOVE', 'MYNA', 'NICOBAR PIGEON', 'NORTHERN CARDINAL', + 'NORTHERN FLICKER', 'NORTHERN GANNET', 'NORTHERN GOSHAWK', 'NORTHERN JACANA', 'NORTHERN MOCKINGBIRD', 'NORTHERN PARULA', 'NORTHERN RED BISHOP', + 'OCELLATED TURKEY', 'OKINAWA RAIL', 'OSPREY', 'OSTRICH', 'PAINTED BUNTIG', 'PALILA', 'PARADISE TANAGER', 'PARUS MAJOR', 'PEACOCK', 'PELICAN', + 'PEREGRINE FALCON', 'PHILIPPINE EAGLE', 'PINK ROBIN', 'PUFFIN', 'PURPLE FINCH', 'PURPLE GALLINULE', 'PURPLE MARTIN', 'PURPLE SWAMPHEN', 'QUETZAL', + 'RAINBOW LORIKEET', 'RAZORBILL', 'RED FACED CORMORANT', 'RED FACED WARBLER', 'RED HEADED DUCK', 'RED HEADED WOODPECKER', 'RED HONEY CREEPER', + 'RED THROATED BEE EATER', 'RED WINGED BLACKBIRD', 'RED WISKERED BULBUL', 'RING-NECKED PHEASANT', 'ROADRUNNER', 'ROBIN', 'ROCK DOVE', 'ROSY FACED LOVEBIRD', + 'ROUGH LEG BUZZARD', 'RUBY THROATED HUMMINGBIRD', 'RUFOUS KINGFISHER', 'RUFUOS MOTMOT', 'SAND MARTIN', 'SCARLET IBIS', 'SCARLET MACAW', 'SHOEBILL', + 'SMITHS LONGSPUR', 'SNOWY EGRET', 'SNOWY OWL', 'SORA', 'SPANGLED COTINGA', 'SPLENDID WREN', 'SPOON BILED SANDPIPER', 'SPOONBILL', 'STEAMER DUCK', + 'STORK BILLED KINGFISHER', 'STRAWBERRY FINCH', 'STRIPPED SWALLOW', 'SUPERB STARLING', 'TAIWAN MAGPIE', 'TAKAHE', 'TASMANIAN HEN', 'TEAL DUCK', + 'TIT MOUSE', 'TOUCHAN', 'TOWNSENDS WARBLER', 'TREE SWALLOW', 'TRUMPTER SWAN', 'TURKEY VULTURE', 'TURQUOISE MOTMOT', 'VARIED THRUSH', + 'VENEZUELIAN TROUPIAL', 'VERMILION FLYCATHER', 'VIOLET GREEN SWALLOW', 'WATTLED CURASSOW', 'WHIMBREL', 'WHITE CHEEKED TURACO', + 'WHITE NECKED RAVEN', 'WHITE TAILED TROPIC', 'WILD TURKEY', 'WILSONS BIRD OF PARADISE', 'WOOD DUCK', 'YELLOW CACIQUE', 'YELLOW HEADED BLACKBIRD'] +""" path = Path(__file__).parent app = Starlette() app.add_middleware(CORSMiddleware, allow_origins=['*'], allow_headers=['X-Requested-With', 'Content-Type']) app.mount('/static', StaticFiles(directory='app/static')) - +""" async def download_file(url, dest): - if dest.exists(): return async with aiohttp.ClientSession() as session: async with session.get(url) as response: data = await response.read() @@ -30,9 +63,9 @@ async def download_file(url, dest): async def setup_learner(): - await download_file(export_file_url, path / export_file_name) + await download_file(export_file_url, path / export_file_name_2) try: - learn = load_learner(path, export_file_name) + learn = pickle.load(open((path / 'models/model.sav'), 'rb')) return learn except RuntimeError as e: if len(e.args) > 0 and 'CPU-only machine' in e.args[0]: @@ -47,23 +80,67 @@ async def setup_learner(): tasks = [asyncio.ensure_future(setup_learner())] learn = loop.run_until_complete(asyncio.gather(*tasks))[0] loop.close() - - +""" +#hey +#rool @app.route('/') async def homepage(request): html_file = path / 'view' / 'index.html' return HTMLResponse(html_file.open().read()) +@app.route('/aboutus') +async def homepage(request): + html_file = path / 'view' / 'aboutus.html' + return HTMLResponse(html_file.open().read()) + +@app.route('/aboutp') +async def homepage(request): + html_file = path / 'view' / 'aboutp.html' + return HTMLResponse(html_file.open().read()) -@app.route('/analyze', methods=['POST']) -async def analyze(request): +@app.route('/classifier') +async def homepage(request): + html_file = path / 'view' / 'classifier.html' + return HTMLResponse(html_file.open().read()) + +@app.route('/analyze_cnn', methods=['POST']) +async def analyze_cnn(request): img_data = await request.form() img_bytes = await (img_data['file'].read()) img = open_image(BytesIO(img_bytes)) - prediction = learn.predict(img)[0] - return JSONResponse({'result': str(prediction)}) + learn2 = load_learner(path / 'models', export_file_name) + pred_class, pred_idx, outputs = learn2.predict(img) #[0] + prediction = learn2.predict(img)[0] + pred_probs = outputs/sum(outputs) + pred_probs = pred_probs.tolist() + predictions = [] + for image_class, output, prob in zip(learn2.data.classes, outputs.tolist(), pred_probs): + output = round(output, 1) + prob = round(prob, 2) + predictions.append( + {"class": image_class.replace("_", " "), "output": output, "prob": prob} + ) + + predictions = sorted(predictions, key=lambda x: x["output"], reverse=True) + predictions = predictions[0:2] + #print({"class": str(pred_class), "predictions": predictions}) + predictions = (predictions)[0] + return JSONResponse({'result': [str(predictions['class']), str(predictions['prob']*100)]}) + +@app.route('/analyze_knn', methods=['POST']) +async def analyze_knn(request): + img_data = await request.form() + img_bytes = await (img_data['file'].read()) + img = IM.open(BytesIO(img_bytes)) + img = img.resize((224, 224)) + img = np.array(img) + img = img.reshape(1, 50176) + learn = pickle.load(open(path / 'models/model.sav', 'rb')) + output_class = learn.predict(img)[0] + + return JSONResponse({'result': str(output_class)}) if __name__ == '__main__': if 'serve' in sys.argv: - uvicorn.run(app=app, host='0.0.0.0', port=5000, log_level="info") + uvicorn.run(app=app, host='0.0.0.0', port=5000, log_level="info") \ No newline at end of file diff --git a/app/static/CNN_pic.png b/app/static/CNN_pic.png new file mode 100644 index 000000000..a836defd4 Binary files /dev/null and b/app/static/CNN_pic.png differ diff --git a/app/static/NTNU_logo.png b/app/static/NTNU_logo.png new file mode 100644 index 000000000..63628b39c Binary files /dev/null and b/app/static/NTNU_logo.png differ diff --git a/app/static/client.js b/app/static/client.js index 84c2c9541..753b9758f 100644 --- a/app/static/client.js +++ b/app/static/client.js @@ -14,14 +14,17 @@ function showPicked(input) { reader.readAsDataURL(input.files[0]); } -function analyze() { +function analyze() { + console.log("Hei Elise <3") var uploadFiles = el("file-input").files; if (uploadFiles.length !== 1) alert("Please select a file to analyze!"); el("analyze-button").innerHTML = "Analyzing..."; + + var xhr = new XMLHttpRequest(); var loc = window.location; - xhr.open("POST", `${loc.protocol}//${loc.hostname}:${loc.port}/analyze`, + xhr.open("POST", `${loc.protocol}//${loc.hostname}:${loc.port}/analyze_cnn`, true); xhr.onerror = function() { alert(xhr.responseText); @@ -29,13 +32,67 @@ function analyze() { xhr.onload = function(e) { if (this.readyState === 4) { var response = JSON.parse(e.target.responseText); - el("result-label").innerHTML = `Result = ${response["result"]}`; + // var response = {"result":[{'class': 'PNEUMONIA', 'output': 0.9, 'prob': 0.93}, {'class': 'NORMAL', 'output': 0.1, 'prob': 0.07}]} + var result = response["result"] + el("result-label").innerHTML = `Result = ${result}`; + var modal = document.getElementById("myModal"); + modal.style.display = "block"; + el("state").innerHTML = `${result[0]}`; + // state.innerHTML = response["result"][0].class + el("percent").innerHTML = result[1]; } el("analyze-button").innerHTML = "Analyze"; }; + var fileData = new FormData(); fileData.append("file", uploadFiles[0]); xhr.send(fileData); } +// Top navigation bar +$(function(){ + var str = '#len'; //increment by 1 up to 1-nelemnts + $(document).ready(function(){ + var i, stop; + i = 1; + stop = 4; //num elements + setInterval(function(){ + if (i > stop){ + return; + } + $('#len'+(i++)).toggleClass('bounce'); + }, 500) + }); +}); + +// Modal for results + +// When the user clicks the button, open the modal +// External modal-button for testing locally +// function openModal(){ + // var response = JSON.parse(e.target.responseText); + // var response = {"result":[{'class': 'PNEUMONIA', 'output': 0.9, 'prob': 0.93}, {'class': 'NORMAL', 'output': 0.1, 'prob': 0.07}]} + // var response = {"result":[{'class': 'NORMAL', 'output': 1.0, 'prob': 1.0}, {'class': 'PNEUMONIA', 'output': 0.0, 'prob': 0.0}]} + // el("result-label").innerHTML = `Result = ${response["result"]}`; + // var modal = document.getElementById("myModal"); + // modal.style.display = "block"; + // el("state").innerHTML = response["result"][0].class + // state.innerHTML = response["result"][0].class + // el("percent").innerHTML = response["result"][0].prob * 100 +// } + + +// When the user clicks on (x), close the modal +function closeModal(){ + var modal = document.getElementById("myModal"); + modal.style.display = "none"; +} + +// When the user clicks anywhere outside of the modal, close it +window.onclick = function(event) { + var modal = document.getElementById("myModal"); + if (event.target === modal) { + modal.style.display = "none"; + } +} \ No newline at end of file diff --git a/app/static/grupo ml.png b/app/static/grupo ml.png new file mode 100644 index 000000000..e93eb9d31 Binary files /dev/null and b/app/static/grupo ml.png differ diff --git a/app/static/logo1.png b/app/static/logo1.png new file mode 100644 index 000000000..c8164aa81 Binary files /dev/null and b/app/static/logo1.png differ diff --git a/app/static/logo2.png b/app/static/logo2.png new file mode 100644 index 000000000..0773097cd Binary files /dev/null and b/app/static/logo2.png differ diff --git a/app/static/logo3.png b/app/static/logo3.png new file mode 100644 index 000000000..28f1b3d6a Binary files /dev/null and b/app/static/logo3.png differ diff --git a/app/static/pneumonia.png b/app/static/pneumonia.png new file mode 100644 index 000000000..23ae46b9f Binary files /dev/null and b/app/static/pneumonia.png differ diff --git a/app/static/style.css b/app/static/style.css index b1065f8de..d85f089c5 100644 --- a/app/static/style.css +++ b/app/static/style.css @@ -1,38 +1,172 @@ body { - background-color: #fff; + background-color: white; + margin: auto; + border-bottom: 0; + line-height: 150%; + } +/*Top navigation bar for the page*/ +.topnav { + overflow: hidden; + background-color: powderblue; + border-bottom: solid 1px silver; + width: 100%; + margin: auto; + + } + + .topnav a { + float: left; + display: block; + color: black; + text-align: center; + padding: 14px 16px; + text-decoration: none; + font-size: 17px; + } + + .topnav a:hover { + background-color: #ddd; + color: black; + } + + .topnav a.active { + background-color: white; + border-bottom: solid 1px white; + color: powderblue; + } + + .topnav .icon { + display: none; + color: black; + } + + @media screen and (max-width: 600px) { + .topnav a:not(:first-child) {display: none;} + .topnav a.icon { + float: right; + display: block; + color: black; + } + } + + @media screen and (max-width: 600px) { + .topnav.responsive {position: relative;} + .topnav.responsive .icon { + position: absolute; + right: 0; + color: black; + display: block; + top: 0; + } + .topnav.responsive a { + float: none; + display: block; + text-align: left; + } + } .no-display { display: none; } +h1 { + margin-top: 0; +} +p{ + font-size: 20px; + font-family: Calibri, serif; +} .center { margin: auto; - padding: 10px 50px; + padding: 5px 50px; text-align: center; - font-size: 14px; + font-size: 15px; +} + +.maintitle{ + font-size: 45px; +} + +.content { + margin-top: 3em; + display: flex; + flex-direction: column; + align-items: center; +} + + +/*everything below here is just setting up the page, so dont worry about it */ + + +@media (min-width: 768px) { + .navbar{ + text-align: center !important; + float: none; + display: inline-block; + } +} + +body { + background-color: rgba(0,0,0,1); + font-weight:600; + text-align:center !important; + color: white; } + + + +.page-title { + opacity: .75 !important; +} + + +.page { + background-color: white; + align-items: center; + margin: auto; + min-height: 100%; + width: 100%; + +} + + .title { font-size: 30px; margin-top: 1em; - margin-bottom: 1em; + margin-bottom: 0; color: #262626; } -.content { - margin-top: 10em; + +.undertitle { + font-size: 22px; + margin-bottom: 2em; + color: #262626; +} + +.header { + text-align: center; + margin-top: 1em; + margin-bottom: 0; } .analyze { - margin-top: 5em; + margin-top: 2em; +} + +.p{ + color: white; } .upload-label { - padding: 10px; + padding: 8px; font-size: 12px; } - +#image-picked { + margin-top: 1em; +} .result-label { margin-top: 0.5em; padding: 10px; @@ -44,21 +178,193 @@ button.choose-file-button { height: 40px; border-radius: 2px; background-color: #ffffff; - border: solid 1px #7052CB; + border: solid 1px #9eddff; font-size: 13px; - color: #7052CB; + color: black; + text-align: center; } button.analyze-button { width: 200px; height: 40px; - border: solid 1px #7052CB; + border: solid 1px #9eddff; border-radius: 2px; - background-color: #7052CB; + background-color: #9eddff; font-size: 13px; - color: #ffffff; + color: black; + text-align: center; } button:focus { outline: 0; } + +.logo_pic{ + width: 70%; + height: 40%; +} + + +/* Modal for the classification results */ +/* The Modal (background) */ +.button { + margin: 0; +} +.modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + padding-top: 100px; /* Location of the box */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: white; /* Fallback color */ + background-color: white; /* Black w/ opacity */ + } + + /* Modal Content */ + .modal-content { + background-color: #fefefe; + margin: auto; + padding: 20px; + border: 1px solid #888; + width: 40%; + position: relative; + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19); + text-align: center; + } + + + /* The Close Button */ +.close { + color: white; + float: right; + font-size: 28px; + font-weight: bold; + } + .close:hover, + .close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + } + .modal-header { + padding: 2px 16px; + background-color: #9eddff; + color: white; + } + + .modal-body {padding: 2px 16px;} + + #state { + color: red; + font-size: 25px; + + } + + #percent { + color: red; + } + + /* Pneumonia page*/ + .content2{ + margin-top: 1em; + display: flex; + flex-direction: row; + /*align-items: center;*/ + } + + .picture { + width: 70%; + float: right; + margin-top: 2em; + padding-top: 2.5em; + + /*margin-right: 10px;*/ + + /*display: flex; + flex-direction: column; + align-items: center;*/ + } + + + .text { + float: left; + width: 50%; + /*border: solid 1px white;*/ + margin-top: 2em; + margin-left: 20px; + color: white; + + + /*display: flex; + flex-direction: column; + align-items: center;*/ + } + + .ingress { + margin: auto; + font-size: 20px; + width: 90%; + color: white; + padding-top: 1.5em; + + } + .button3 { + background-color: #9eddff; + border: none; + color: black; + padding: 15px 15px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: auto; + cursor: pointer; + display: flex; + justify-content: center; + width: 200px; + } + + .NTNU_pic { + padding-top: 5em; + width: 50%; + height: 50%; + justify-content: center; +} + + @media only screen and (max-width: 1020px) { + .content2{ + flex-direction: column; + justify-content: center; + align-items: center; + } + .text { + width: 100%; + } + .picture { + min-width: 100%; + } + + .links{ + background-color: black; + color: black; + } + + links:hover{ + background-color: #9eddff; + color: #9eddff; + + } + + /*.CNN_pic { + width: 80%; + height: 80%; + }*/ + + + + +} \ No newline at end of file diff --git a/app/view/aboutp.html b/app/view/aboutp.html new file mode 100644 index 000000000..0070d8f53 --- /dev/null +++ b/app/view/aboutp.html @@ -0,0 +1,51 @@ + + + About Pneumonia + + + + + + + +
+ Home + Classifier + + + About Pneumonia + + About Us + + + +
+
+
+

Pneumonia

+

Pneumonia kills more children than any other infectious disease. Globally, close to 1 million + under five children die from this preventable disease every year, the equivalent of more than 2,500 dying every day. + That is more than the death tolls of diarrhoea, malaria and HIV combined for this age group. Yet you will hear of no global + campaign or cause to end pneumonia.

+
+
+

What is Pneumonia

+

Pneumonia is an infection of the lungs, and is most often bacterial or viral, though it can also be caused by fungus or parasites. + The mucus created in the lungs provokes coughing, shortness of breath and fever, among other symptoms. As the lungs fill with fluid + their ability to intake oxygen decreases. The disease can be acquired in many different ways in the community, + usually from breathing the germs into the lungs. It is also very commonly acquired in hospital settings, and + is frequently associated with or provoked by other conditions. There are 30 different known causes of pneumonia, + and consequently there is no silver bullet to eradicate it. However, a range of effective strategies does exist to + control the disease and considerably reduce its deadly impact. + +

+ Read more about it here +
+
+ pneumonia pic +
+
+
+
+ + \ No newline at end of file diff --git a/app/view/aboutus.html b/app/view/aboutus.html new file mode 100644 index 000000000..b80dfec8b --- /dev/null +++ b/app/view/aboutus.html @@ -0,0 +1,49 @@ + + + About us + + + + + + +
+ Home + + Classifier + + About Pneumonia + + About Us + + + +
+ +
+
+

The Research Group

+
+ Group picture + +




This web page is made as part of a group project in the + course TDT4173 Machine Learning at the Norwegian University
of Science and Technology. + More about the course here. +

Our group consisted of three 4-year students; Anders, Marianne, + and Elise. All of us are enrolled at the Norwegian University
of Science and Technology in the + study program Engineering and ICT. More about the program here. +

Our group worked for 2.5 months on the problem of automatically diagnosing patients. + We trained a machine learning model
consisting of + a neural network with 50 layers, called a Residual Neural Network, during our project. We trained it + to classify real
medical chest x-ray images into two groups: normal and abnormal. The images we used + are of children with and without pneumonia. After
training, our model correctly classified 820 of + 844 x-rays with pneumonia and 318 out of 327 normal x-rays. Even though the model
cannot guarantee + exact results, it achieved an impressively 97.18% accuracy. We still recommend checking with your + doctor
to be sure of your diagnosis.
+ +

+
+
+
+ + diff --git a/app/view/classifier.html b/app/view/classifier.html new file mode 100644 index 000000000..f90307939 --- /dev/null +++ b/app/view/classifier.html @@ -0,0 +1,91 @@ + + + Pneumonia Classifier + + + + + + +
+ Home + Classifier + + + About Pneumonia + + About Us + + + +
+
+
+
+
+





Our Pneumonia Classifier - A Residual Neural Network

+ +

+
+
+

This model detects pneumonia in chest X-rays. You can try the model below by uploading an x-ray + image of a chest and press "Analyze".

+
+ +
+ +
+ Chosen Image +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + + + + + + + +
+
+ \ No newline at end of file diff --git a/app/view/index.html b/app/view/index.html index 6642e26f5..14fd350e9 100644 --- a/app/view/index.html +++ b/app/view/index.html @@ -1,41 +1,58 @@ - - + + + Pneumonia Classifier - + + - -
-
-
Classify Bear Images 🐻
-

- Use images of teddy bears, black bears, grizzly bears, or - all three! -

-
-
- -
- -
- -
-
- Chosen Image -
-
- -
-
- -
-
+ + + +
+
+
+ +
+







+
+ Group picture +
+ +

      + What if already busy doctors did not have to analyze your x-rays in order
to diagnose you, but a machine did it instead? + How you say?

Well, if doctors can learn how to read x-rays, then why should not machines
be able to learn it too.

+ We have developed and trained a machine
learning model to do just that, and you can test it out on your x-rays
by navigating to the Classifier-page. + +

+
+ + + + + + + + + + +
- - + \ No newline at end of file