Compare commits
4 Commits
5da1ecb2e2
...
354d5fdbd5
Author | SHA1 | Date | |
---|---|---|---|
|
354d5fdbd5 | ||
|
d70592fc64 | ||
|
52335870fd | ||
|
b7c7f8e066 |
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -11,7 +11,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"module": "flask",
|
"module": "flask",
|
||||||
"env": {
|
"env": {
|
||||||
"FLASK_APP": "webApp.py",
|
"FLASK_APP": "src/webApp.py",
|
||||||
"FLASK_DEBUG": "1"
|
"FLASK_DEBUG": "1"
|
||||||
},
|
},
|
||||||
"args": ["run", "--no-debugger", "--no-reload"]
|
"args": ["run", "--no-debugger", "--no-reload"]
|
||||||
|
18
README.md
18
README.md
@ -2,21 +2,23 @@
|
|||||||
|
|
||||||
Сервис: http://kb.athene.tech/swagger-ui/index.html
|
Сервис: http://kb.athene.tech/swagger-ui/index.html
|
||||||
|
|
||||||
Ручная установка зависимостей:
|
Настройка виртуальной среды и установка зависимостей:
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
pip install -r requirements.txt
|
python -m venv --clear .venv
|
||||||
```
|
|
||||||
|
|
||||||
Ручная установка зависимостей для mac с Apple Silicon:
|
.venv\Scripts\activate.bat
|
||||||
|
# или
|
||||||
|
.\.venv\Scripts\Activate.ps1
|
||||||
|
# или
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
```commandline
|
python -m pip install -r requirements.txt
|
||||||
pip install -r requirements-mac.txt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Запуск:
|
Запуск:
|
||||||
|
|
||||||
```commandline
|
```commandline
|
||||||
main.py <Ontology UID> <Image Path>
|
python main.py <Ontology UID> <Image Path>
|
||||||
main.py 5cc5570b-6ed9-3b33-9db4-bdb8ecb9f890 "test-data/lectionAudi/2021-03-12 13-48-31.JPG"
|
python main.py 5cc5570b-6ed9-3b33-9db4-bdb8ecb9f890 "test-data/lectionAudi/2021-03-12 13-48-31.JPG"
|
||||||
```
|
```
|
||||||
|
@ -3,14 +3,11 @@ import sys
|
|||||||
|
|
||||||
import cv2 as cv
|
import cv2 as cv
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import requests
|
|
||||||
|
|
||||||
import imageWorking
|
import imageWorking
|
||||||
import neuralNetwork
|
import neuralNetwork
|
||||||
import ontologyWorking
|
import ontologyWorking
|
||||||
|
|
||||||
url = 'http://kb.athene.tech/api/1.0/ontology/'
|
|
||||||
|
|
||||||
|
|
||||||
def analyze_base(ontology_uid: str, image: np.ndarray, queries: list[str]) -> tuple[2]:
|
def analyze_base(ontology_uid: str, image: np.ndarray, queries: list[str]) -> tuple[2]:
|
||||||
'''
|
'''
|
||||||
@ -18,8 +15,6 @@ def analyze_base(ontology_uid: str, image: np.ndarray, queries: list[str]) -> tu
|
|||||||
@param ontology_uid: УИД онтологии.
|
@param ontology_uid: УИД онтологии.
|
||||||
@param image: Изображение.
|
@param image: Изображение.
|
||||||
'''
|
'''
|
||||||
if not ontologyWorking.is_ontology_exists(ontology_uid, url):
|
|
||||||
raise Exception(f'Онтология с uid {ontology_uid} не существует')
|
|
||||||
if image is None:
|
if image is None:
|
||||||
raise Exception(f'Изображение не указано')
|
raise Exception(f'Изображение не указано')
|
||||||
model = neuralNetwork.load_model()
|
model = neuralNetwork.load_model()
|
||||||
@ -38,18 +33,9 @@ def analyze_base(ontology_uid: str, image: np.ndarray, queries: list[str]) -> tu
|
|||||||
object_properties += request[0]
|
object_properties += request[0]
|
||||||
data_properties += request[1]
|
data_properties += request[1]
|
||||||
|
|
||||||
# Формирование данных для запроса к сервису работы с онтологиями.
|
|
||||||
data = {
|
|
||||||
'data':
|
|
||||||
{
|
|
||||||
'objectPropertyAssertions': object_properties,
|
|
||||||
'dataPropertyAssertions': data_properties
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params = '&'.join([f'names={query}' for query in queries])
|
|
||||||
|
|
||||||
# Выполнение запроса.
|
# Выполнение запроса к сервису работы с онтологиями
|
||||||
response = requests.post(url + f'{ontology_uid}/query/multi?{params}', json=data).json()
|
response = ontologyWorking.analyze(ontology_uid, object_properties, data_properties, queries)
|
||||||
|
|
||||||
return results, response
|
return results, response
|
||||||
|
|
@ -2,15 +2,18 @@ import numpy as np
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
def is_ontology_exists(uid: str, url: str) -> bool:
|
url = 'http://kb.athene.tech/api/1.0/ontology/'
|
||||||
|
|
||||||
|
|
||||||
|
def is_ontology_exists(ontology_uid: str, url: str) -> bool:
|
||||||
'''
|
'''
|
||||||
Проверяет, существует ли онтология в сервисе.
|
Проверяет, существует ли онтология в сервисе.
|
||||||
@param uid: УИД онтологии.
|
@param ontology_uid: УИД онтологии.
|
||||||
@param url: Базовый URL сервиса.
|
@param url: Базовый URL сервиса.
|
||||||
'''
|
'''
|
||||||
list_ontologies = requests.get(url).json()['response']['items']
|
list_ontologies = requests.get(url).json()['response']['items']
|
||||||
for onto in list_ontologies:
|
for onto in list_ontologies:
|
||||||
if onto['uid'] == uid:
|
if onto['uid'] == ontology_uid:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -61,3 +64,30 @@ def get_request_data(entities: dict, objects: np.ndarray, confs: np.ndarray, box
|
|||||||
data_properties.append({'domain': entity, 'property': 'hasConfidence', 'value': float(conf)})
|
data_properties.append({'domain': entity, 'property': 'hasConfidence', 'value': float(conf)})
|
||||||
|
|
||||||
return object_properties, data_properties
|
return object_properties, data_properties
|
||||||
|
|
||||||
|
|
||||||
|
def analyze(ontology_uid: str, object_properties: list, data_properties: list, queries: list[str]) -> tuple[2]:
|
||||||
|
'''
|
||||||
|
Базовая функция анализа.
|
||||||
|
@param ontology_uid: УИД онтологии.
|
||||||
|
@param object_properties: Объектные свойства.
|
||||||
|
@param data_properties: Свойства данных.
|
||||||
|
@param queries: Список запросов для запуска.
|
||||||
|
'''
|
||||||
|
if not is_ontology_exists(ontology_uid, url):
|
||||||
|
raise Exception(f'Онтология с uid {ontology_uid} не существует')
|
||||||
|
|
||||||
|
# Формирование данных для запроса к сервису работы с онтологиями.
|
||||||
|
data = {
|
||||||
|
'data':
|
||||||
|
{
|
||||||
|
'objectPropertyAssertions': object_properties,
|
||||||
|
'dataPropertyAssertions': data_properties
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params = '&'.join([f'names={query}' for query in queries])
|
||||||
|
|
||||||
|
# Выполнение запроса.
|
||||||
|
response = requests.post(url + f'{ontology_uid}/query/multi?{params}', json=data).json()
|
||||||
|
|
||||||
|
return response
|
48
src/webApp.py
Normal file
48
src/webApp.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import base64
|
||||||
|
import cv2 as cv
|
||||||
|
from flask import Flask, redirect, request
|
||||||
|
import numpy
|
||||||
|
from imageWorking import get_image_buf_as_array
|
||||||
|
from main import analyze_base
|
||||||
|
|
||||||
|
app = Flask(__name__, static_folder = "../static", static_url_path = "/")
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def main():
|
||||||
|
return redirect('index.html')
|
||||||
|
|
||||||
|
@app.route("/analyze", methods=["POST"])
|
||||||
|
def analyze():
|
||||||
|
# Первоначальные проверки.
|
||||||
|
if 'image' not in request.files or request.files['image'].filename == '':
|
||||||
|
return {
|
||||||
|
'success': False,
|
||||||
|
'error': 'Укажите изображение',
|
||||||
|
}
|
||||||
|
if 'ontology' in request.files and request.files['ontology'].filename != '':
|
||||||
|
return {
|
||||||
|
'success': False,
|
||||||
|
'error': 'Загрузка онтологии ещё не реализована',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Подготовка исходного изображения.
|
||||||
|
image_source = request.files['image'].read();
|
||||||
|
image_source = numpy.fromstring(image_source, numpy.uint8)
|
||||||
|
image_source = get_image_buf_as_array(image_source)
|
||||||
|
|
||||||
|
# Подготовка прочих данных и выполнение запроса.
|
||||||
|
queries = request.form['queries'].split(',') if request.form['queries'] is not None else [ ]
|
||||||
|
results, response = analyze_base('5cc5570b-6ed9-3b33-9db4-bdb8ecb9f890', image_source, queries)
|
||||||
|
|
||||||
|
# Подготовка изображения с ответом.
|
||||||
|
image_result = results[0].plot()
|
||||||
|
image_result = cv.cvtColor(image_result, cv.COLOR_BGR2RGB)
|
||||||
|
image_result = cv.imencode(".jpg", image_result)[1]
|
||||||
|
image_result = base64.b64encode(image_result).decode("utf-8")
|
||||||
|
|
||||||
|
# Вывод ответа.
|
||||||
|
return {
|
||||||
|
'success': True,
|
||||||
|
'data': response,
|
||||||
|
'image': image_result,
|
||||||
|
}
|
@ -1,32 +1,57 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" class="h-100">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Анализ аудиторий</title>
|
<title>Анализ аудиторий</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous" />
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
<p>
|
<body class="bg-body-secondary h-100 d-flex align-items-center">
|
||||||
Загрузите изображение в поле ниже, чтобы проверить, на фотография пустая
|
<div class="container py-3">
|
||||||
или заполненная аудитория.
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg">
|
||||||
|
<p class="alert alert-info">
|
||||||
|
Загрузите изображение в поле ниже, чтобы проверить, на
|
||||||
|
фотография пустая или заполненная аудитория.
|
||||||
</p>
|
</p>
|
||||||
<form id="uploadForm" action="analyze">
|
<form id="uploadForm" action="analyze">
|
||||||
<div>
|
<div>
|
||||||
<label for="image">Нажмите, чтобы загрузить изображение</label>
|
<label for="image" class="form-label">Нажмите, чтобы загрузить изображение</label>
|
||||||
<input type="file" name="image" id="image" />
|
<input type="file" class="form-control" name="image" id="image" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="ontology">Онтология предметной области</label>
|
<label for="ontology" class="form-label">Онтология предметной области</label>
|
||||||
<input type="file" name="ontology" id="ontology" />
|
<input type="file" class="form-control" name="ontology" id="ontology" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button type="submit">Отправить</button>
|
<label for="queries" class="form-label">Набор запросов для запуска</label>
|
||||||
|
<input type="text" class="form-control" name="queries" id="queries"
|
||||||
|
value="QueryGetNotEmpty,QueryGetCheck,QueryGetEmpty" />
|
||||||
|
</div>
|
||||||
|
<div class="my-3">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
Отправить
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
<img src="" alt="Результат" id="imgslot" />
|
<div class="col-lg">
|
||||||
|
<img src="none.png" alt="Результат" id="imgslot" class="w-100" />
|
||||||
|
<div id="queriesResult"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<script>
|
<script>
|
||||||
document
|
document
|
||||||
.getElementById("uploadForm")
|
.getElementById("uploadForm")
|
||||||
@ -36,14 +61,40 @@
|
|||||||
fetch("/analyze", { method: "POST", body: data })
|
fetch("/analyze", { method: "POST", body: data })
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
debugger;
|
const img = document.getElementById("imgslot");
|
||||||
|
const queriesResult = document.getElementById("queriesResult");
|
||||||
|
|
||||||
|
img.src = "none.png";
|
||||||
if (data.image) {
|
if (data.image) {
|
||||||
document.getElementById("imgslot").src =
|
img.src = "data:image/jpg;base64," + data.image;
|
||||||
"data:image/jpg;base64," + data.image;
|
}
|
||||||
|
|
||||||
|
queriesResult.innerHTML = "";
|
||||||
|
if (data.data && data.data.response) {
|
||||||
|
for (const [query, result] of Object.entries(
|
||||||
|
data.data.response
|
||||||
|
)) {
|
||||||
|
// Отрисовка результата запросов.
|
||||||
|
const markup = `
|
||||||
|
<h1 class="display-6">${query}</h1>
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<tr>
|
||||||
|
${result.columns.map((column) => `<th>${column}</th>`).join("")}
|
||||||
|
</tr>
|
||||||
|
${result.rows.map(
|
||||||
|
(row) =>
|
||||||
|
`<tr>${Object.entries(row)
|
||||||
|
.map(([key, value]) => `<td>${value.value}</td>`)
|
||||||
|
.join("")}</tr>`
|
||||||
|
)}
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
queriesResult.innerHTML += markup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log(data);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
BIN
static/none.png
Normal file
BIN
static/none.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
36
webApp.py
36
webApp.py
@ -1,36 +0,0 @@
|
|||||||
import base64
|
|
||||||
import cv2 as cv
|
|
||||||
from flask import Flask, redirect, request
|
|
||||||
import numpy
|
|
||||||
from imageWorking import get_image_buf_as_array
|
|
||||||
from main import analyze_base
|
|
||||||
|
|
||||||
app = Flask(__name__, static_url_path = "/")
|
|
||||||
|
|
||||||
@app.route("/")
|
|
||||||
def main():
|
|
||||||
return redirect('index.html')
|
|
||||||
|
|
||||||
@app.route("/analyze", methods=["POST"])
|
|
||||||
def analyze():
|
|
||||||
if 'image' not in request.files or request.files['image'].filename == '':
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'error': 'Укажите изображение',
|
|
||||||
}
|
|
||||||
if 'ontology' in request.files and request.files['ontology'].filename != '':
|
|
||||||
return {
|
|
||||||
'success': False,
|
|
||||||
'error': 'Загрузка онтологии ещё не реализована',
|
|
||||||
}
|
|
||||||
img = request.files['image'].read();
|
|
||||||
img = numpy.fromstring(img, numpy.uint8)
|
|
||||||
img = get_image_buf_as_array(img)
|
|
||||||
queries = [ 'QueryGetNotEmpty', 'QueryGetCheck', 'QueryGetEmpty' ]
|
|
||||||
results, response = analyze_base('5cc5570b-6ed9-3b33-9db4-bdb8ecb9f890', img, queries)
|
|
||||||
imencoded = cv.imencode(".jpg", results[0].plot())[1]
|
|
||||||
return {
|
|
||||||
'success': True,
|
|
||||||
'data': response,
|
|
||||||
'image': base64.b64encode(imencoded).decode("utf-8"),
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user