index.html을 작성한다.
이미지를 업로드 하면, 미리보기를 보여주는 코드
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File Upload with Image Preview</title>
<!-- 외부 CSS 파일 불러오기 -->
<link rel="stylesheet" href="uploader-styles.css">
</head>
<body>
<h2>File Upload & Image Preview</h2>
<p class="lead">No Plugins <b>Just Javascript</b></p>
<!-- Upload -->
<form id="file-upload-form" class="uploader">
<input id="file-upload" type="file" name="fileUpload" accept="image/*" />
<label for="file-upload" id="file-drag">
<img id="file-image" src="#" alt="Preview" class="hidden">
<div id="start">
<i class="fa fa-download" aria-hidden="true"></i>
<div>Select a file or drag here</div>
<div id="notimage" class="hidden">Please select an image</div>
<span id="file-upload-btn" class="btn btn-primary">Select a file</span>
</div>
<div id="response" class="hidden">
<div id="messages"></div>
<progress class="progress" id="file-progress" value="0">
<span>0</span>%
</progress>
</div>
</label>
</form>
<!-- 스크립트 파일 연결 -->
<script src="script.js"></script>
</body>
</html>
2. 스타일시트를 정의한다.
uploader-styles.css
/* Imports */
@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css);
@import url('https://fonts.googleapis.com/css?family=Roboto');
/* Vars and Reset */
$theme: #454cad;
$dark-text: #5f6982;
html,
body,
* {
box-sizing: border-box;
font-size: 16px;
}
html,
body {
height: 100%;
text-align: center;
}
body {
padding: 2rem;
background: #f8f8f8;
}
h2 {
font-family: "Roboto", sans-serif;
font-size: 26px;
line-height: 1;
color: #454cad;
margin-bottom: 0;
}
p {
font-family: "Roboto", sans-serif;
font-size: 18px;
color: #5f6982;
}
/* Upload Demo */
.uploader {
display: block;
clear: both;
margin: 0 auto;
width: 100%;
max-width: 600px;
}
.uploader label {
float: left;
clear: both;
width: 100%;
padding: 2rem 1.5rem;
text-align: center;
background: #fff;
border-radius: 7px;
border: 3px solid #eee;
transition: all 0.2s ease;
user-select: none;
}
.uploader label:hover {
border-color: #454cad;
}
.uploader label.hover {
border: 3px solid #454cad;
box-shadow: inset 0 0 0 6px #eee;
}
.uploader #start {
float: left;
clear: both;
width: 100%;
}
.uploader #start.hidden {
display: none;
}
.uploader #start i.fa {
font-size: 50px;
margin-bottom: 1rem;
transition: all 0.2s ease-in-out;
}
.uploader #response {
float: left;
clear: both;
width: 100%;
}
.uploader #response.hidden {
display: none;
}
.uploader #response #messages {
margin-bottom: 0.5rem;
}
.uploader #file-image {
display: inline;
margin: 0 auto 0.5rem auto;
width: auto;
height: auto;
max-width: 180px;
}
.uploader #file-image.hidden {
display: none;
}
.uploader #notimage {
display: block;
float: left;
clear: both;
width: 100%;
}
.uploader #notimage.hidden {
display: none;
}
.uploader progress,
.uploader .progress {
display: inline;
clear: both;
margin: 0 auto;
width: 100%;
max-width: 180px;
height: 8px;
border: 0;
border-radius: 4px;
background-color: #eee;
overflow: hidden;
}
.uploader .progress[value]::-webkit-progress-bar {
border-radius: 4px;
background-color: #eee;
}
.uploader .progress[value]::-webkit-progress-value {
background: linear-gradient(to right, darken(#454cad, 8%) 0%, #454cad 50%);
border-radius: 4px;
}
.uploader .progress[value]::-moz-progress-bar {
background: linear-gradient(to right, darken(#454cad, 8%) 0%, #454cad 50%);
border-radius: 4px;
}
.uploader input[type="file"] {
display: none;
}
.uploader div {
margin: 0 0 0.5rem 0;
color: #5f6982;
}
.uploader .btn {
display: inline-block;
margin: 0.5rem 0.5rem 1rem 0.5rem;
clear: both;
font-family: inherit;
font-weight: 700;
font-size: 14px;
text-decoration: none;
text-transform: initial;
border: none;
border-radius: 0.2rem;
outline: none;
padding: 0 1rem;
height: 36px;
line-height: 36px;
color: #fff;
transition: all 0.2s ease-in-out;
box-sizing: border-box;
background: #454cad;
border-color: #454cad;
cursor: pointer;
}
3. 자바스크립트 파일
script.js
// File Upload
//
function ekUpload(){
function Init() {
console.log("Upload Initialised");
var fileSelect = document.getElementById('file-upload'),
fileDrag = document.getElementById('file-drag'),
submitButton = document.getElementById('submit-button');
fileSelect.addEventListener('change', fileSelectHandler, false);
// Is XHR2 available?
var xhr = new XMLHttpRequest();
if (xhr.upload) {
// File Drop
fileDrag.addEventListener('dragover', fileDragHover, false);
fileDrag.addEventListener('dragleave', fileDragHover, false);
fileDrag.addEventListener('drop', fileSelectHandler, false);
}
}
function fileDragHover(e) {
var fileDrag = document.getElementById('file-drag');
e.stopPropagation();
e.preventDefault();
fileDrag.className = (e.type === 'dragover' ? 'hover' : 'modal-body file-upload');
}
function fileSelectHandler(e) {
// Fetch FileList object
var files = e.target.files || e.dataTransfer.files;
// Cancel event and hover styling
fileDragHover(e);
// Process all File objects
for (var i = 0, f; f = files[i]; i++) {
parseFile(f);
uploadFile(f);
}
}
// Output
function output(msg) {
// Response
var m = document.getElementById('messages');
m.innerHTML = msg;
}
function parseFile(file) {
console.log(file.name);
output(
'<strong>' + encodeURI(file.name) + '</strong>'
);
// var fileType = file.type;
// console.log(fileType);
var imageName = file.name;
var isGood = (/\.(?=gif|jpg|png|jpeg)/gi).test(imageName);
if (isGood) {
document.getElementById('start').classList.add("hidden");
document.getElementById('response').classList.remove("hidden");
document.getElementById('notimage').classList.add("hidden");
// Thumbnail Preview
document.getElementById('file-image').classList.remove("hidden");
document.getElementById('file-image').src = URL.createObjectURL(file);
}
else {
document.getElementById('file-image').classList.add("hidden");
document.getElementById('notimage').classList.remove("hidden");
document.getElementById('start').classList.remove("hidden");
document.getElementById('response').classList.add("hidden");
document.getElementById("file-upload-form").reset();
}
}
function setProgressMaxValue(e) {
var pBar = document.getElementById('file-progress');
if (e.lengthComputable) {
pBar.max = e.total;
}
}
function updateFileProgress(e) {
var pBar = document.getElementById('file-progress');
if (e.lengthComputable) {
pBar.value = e.loaded;
}
}
function uploadFile(file) {
var xhr = new XMLHttpRequest(),
fileInput = document.getElementById('class-roster-file'),
pBar = document.getElementById('file-progress'),
fileSizeLimit = 1024; // In MB
if (xhr.upload) {
// Check if file is less than x MB
if (file.size <= fileSizeLimit * 1024 * 1024) {
// Progress bar
pBar.style.display = 'inline';
xhr.upload.addEventListener('loadstart', setProgressMaxValue, false);
xhr.upload.addEventListener('progress', updateFileProgress, false);
// File received / failed
xhr.onreadystatechange = function(e) {
if (xhr.readyState == 4) {
// Everything is good!
// progress.className = (xhr.status == 200 ? "success" : "failure");
// document.location.reload(true);
}
};
// Start upload
xhr.open('POST', document.getElementById('file-upload-form').action, true);
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('X-File-Size', file.size);
xhr.setRequestHeader('Content-Type', 'multipart/form-data');
xhr.send(file);
} else {
output('Please upload a smaller file (< ' + fileSizeLimit + ' MB).');
}
}
}
// Check for the various File API support.
if (window.File && window.FileList && window.FileReader) {
Init();
} else {
document.getElementById('file-drag').style.display = 'none';
}
}
ekUpload();
4. 티쳐블머신 모델을 가져온다.
- 모델 다운로드 후, ftp로 /my_model/ 폴더에 넣어둔다.
- webcam은 https가 있어야만 작동하므로 webcam 관련 코드를 삭제한다.
- 브라우저 상에서 f12(개발자모드)로 들어가서, 업로드 이미지 위치를 찾아 인식분류 대상 이미지 위치로 코드를 수정한다.
다음 영상을 참고하여, 코드를 삭제한다.
https://www.youtube.com/watch?v=UzxqGnsNk1g
<div>Teachable Machine Image Model</div>
<button type="button" onclick="init()">Start</button>
<div id="webcam-container"></div>
<div id="label-container"></div>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@latest/dist/teachablemachine-image.min.js"></script>
<script type="text/javascript">
// More API functions here:
// https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/image
// the link to your model provided by Teachable Machine export panel
const URL = "./my_model/";
let model, webcam, labelContainer, maxPredictions;
// Load the image model and setup the webcam
async function init() {
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
// load the model and metadata
// Refer to tmImage.loadFromFiles() in the API to support files from a file picker
// or files from your local hard drive
// Note: the pose library adds "tmImage" object to your window (window.tmImage)
model = await tmImage.load(modelURL, metadataURL);
maxPredictions = model.getTotalClasses();
// Convenience function to setup a webcam
const flip = true; // whether to flip the webcam
webcam = new tmImage.Webcam(200, 200, flip); // width, height, flip
await webcam.setup(); // request access to the webcam
await webcam.play();
window.requestAnimationFrame(loop);
// append elements to the DOM
document.getElementById("webcam-container").appendChild(webcam.canvas);
labelContainer = document.getElementById("label-container");
for (let i = 0; i < maxPredictions; i++) { // and class labels
labelContainer.appendChild(document.createElement("div"));
}
}
async function loop() {
webcam.update(); // update the webcam frame
await predict();
window.requestAnimationFrame(loop);
}
// run the webcam image through the image model
async function predict() {
// predict can take in an image, video or canvas html element
const prediction = await model.predict(webcam.canvas);
for (let i = 0; i < maxPredictions; i++) {
const classPrediction =
prediction[i].className + ": " + prediction[i].probability.toFixed(2);
labelContainer.childNodes[i].innerHTML = classPrediction;
}
}
</script>
'프로젝트' 카테고리의 다른 글
[html] CORB 위반 (0) | 2024.04.11 |
---|---|
[라즈베리파이-아두이노] 분리수거 휴지통 만들기 (0) | 2023.07.10 |
Comment