made ai analysis api and tested it. 25TPS using gunicorn app:app -w 12 -b 127.0.0.1:8080
@fc1d4dbbd0dc65b2d522b17d81fd01455ad2cbf8
--- action.py
+++ action.py
... | ... | @@ -1,7 +1,7 @@ |
1 | 1 |
from flask_restx import Resource, Namespace |
2 |
-from flask import request |
|
3 |
-from werkzeug.utils import secure_filename |
|
2 |
+from flask import request, jsonify |
|
4 | 3 |
import os |
4 |
+import json |
|
5 | 5 |
from database.database import DB |
6 | 6 |
import torch |
7 | 7 |
from torchvision.transforms import ToTensor |
... | ... | @@ -9,10 +9,27 @@ |
9 | 9 |
from model.AttentiveRNN import AttentiveRNN |
10 | 10 |
from model.Classifier import Resnet as Classifier |
11 | 11 |
from subfuction.image_crop import crop_image |
12 |
+import numpy as np |
|
13 |
+import cv2 |
|
12 | 14 |
|
15 |
+db = DB() |
|
13 | 16 |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') |
14 | 17 |
|
15 |
-paths = os.getcwd() |
|
18 |
+# pre-loading models |
|
19 |
+arnn = AttentiveRNN(6, 3, 2) |
|
20 |
+arnn.eval() |
|
21 |
+arnn.load_state_dict(torch.load("weights/ARNN_trained_weight_6_3_2.pt")) |
|
22 |
+arnn.to(device=device) |
|
23 |
+ |
|
24 |
+classifier = Classifier() |
|
25 |
+classifier.eval() |
|
26 |
+classifier.load_state_dict(torch.load("weights/Classifier_512.pt")) |
|
27 |
+classifier.to(device=device) |
|
28 |
+ |
|
29 |
+tf_toTensor = ToTensor() |
|
30 |
+crop_size = (512, 512) |
|
31 |
+start_point = (750, 450) |
|
32 |
+root_dir = os.getcwd() |
|
16 | 33 |
|
17 | 34 |
Action = Namespace( |
18 | 35 |
name="Action", |
... | ... | @@ -20,17 +37,17 @@ |
20 | 37 |
) |
21 | 38 |
|
22 | 39 |
|
23 |
[email protected]('/image_summit') |
|
24 |
-class fileUpload(Resource): |
|
25 |
- @Action.doc(responses={200: 'Success'}) |
|
26 |
- @Action.doc(responses={500: 'Register Failed'}) |
|
27 |
- def post(self): |
|
28 |
- if request.method == 'POST': |
|
29 |
- f = request.files['file'] |
|
30 |
- f.save(secure_filename(f.filename)) |
|
31 |
- return { |
|
32 |
- 'save': 'done' # str으로 반환하여 return |
|
33 |
- }, 200 |
|
40 |
+# @Action.route('/image_summit') |
|
41 |
+# class fileUpload(Resource): |
|
42 |
+# @Action.doc(responses={200: 'Success'}) |
|
43 |
+# @Action.doc(responses={500: 'Register Failed'}) |
|
44 |
+# def post(self): |
|
45 |
+# if request.method == 'POST': |
|
46 |
+# f = request.files['file'] |
|
47 |
+# f.save(secure_filename(f.filename)) |
|
48 |
+# return { |
|
49 |
+# 'save': 'done' # str으로 반환하여 return |
|
50 |
+# }, 200 |
|
34 | 51 |
|
35 | 52 |
|
36 | 53 |
@Action.route('/image_anal') |
... | ... | @@ -38,48 +55,49 @@ |
38 | 55 |
@Action.doc(responses={200: 'Success'}) |
39 | 56 |
@Action.doc(responses={500: 'Register Failed'}) |
40 | 57 |
def post(self): |
41 |
- if request.method == 'POST': |
|
42 |
- db = DB() |
|
43 |
- arnn = AttentiveRNN(6, 3, 2) |
|
44 |
- arnn.load_state_dict(torch.load("weights/ARNN_trained_weight_6_3_2.pt")) |
|
45 |
- arnn.to(device=device) |
|
46 |
- crop_size = (512, 512) |
|
47 |
- start_point = (750, 450) |
|
48 |
- tf_toTensor = ToTensor() |
|
49 |
- classifier = Classifier() |
|
50 |
- classifier.load_state_dict(torch.load("weights/Classifier_512.pt")) |
|
51 |
- classifier.to(device=device) |
|
52 |
- dir = os.getcwd() |
|
53 |
- lat = float(request.json['gps_x']) |
|
54 |
- lon = float(request.json['gps_y']) |
|
55 |
- filename = request.json['filename'] |
|
56 |
- file_type = request.json['file_type'] |
|
57 |
- total_path = dir + os.path.sep + filename + file_type |
|
58 |
- image = crop_image(total_path, crop_size, start_point) |
|
59 |
- if not image: |
|
60 |
- return { |
|
61 |
- 'node': (lat, lon), |
|
62 |
- 'rain': None, |
|
63 |
- }, 500 |
|
64 |
- image_tensor = tf_toTensor(image) |
|
65 |
- image_tensor = image_tensor.unsqueeze(0) |
|
66 |
- image_tensor = image_tensor.to(device) |
|
58 |
+ # Extracting JSON data |
|
59 |
+ json_data = request.form.get('data') |
|
60 |
+ if not json_data: |
|
61 |
+ return jsonify({"message": "Missing JSON data"}), 400 |
|
62 |
+ data = json.loads(json_data) |
|
63 |
+ |
|
64 |
+ lat = float(data['gps_x']) |
|
65 |
+ lon = float(data['gps_y']) |
|
66 |
+ filename = data['filename'] |
|
67 |
+ file_type = data['file_type'] |
|
68 |
+ |
|
69 |
+ uploaded_file = request.files.get('file') |
|
70 |
+ file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8) |
|
71 |
+ image = cv2.imdecode(file_bytes, cv2.IMREAD_COLOR) |
|
72 |
+ |
|
73 |
+ image = crop_image(image, crop_size, start_point) |
|
74 |
+ |
|
75 |
+ image_tensor = tf_toTensor(image) |
|
76 |
+ image_tensor = image_tensor.unsqueeze(0) |
|
77 |
+ image_tensor = image_tensor.to(device) |
|
78 |
+ with torch.no_grad(): |
|
67 | 79 |
image_arnn = arnn(image_tensor) |
80 |
+ image_tensor.cpu() |
|
81 |
+ del image_tensor |
|
68 | 82 |
result = classifier(image_arnn['x']) |
69 |
- result = result.to("cpu") |
|
70 |
- _, predicted = torch.max(result.data, 1) |
|
71 |
- if predicted == 0: |
|
72 |
- rain = False |
|
73 |
- else: # elif result == 1 |
|
74 |
- rain = True |
|
75 |
- user_id = 'test' |
|
76 |
- action_success = True |
|
77 |
- action_id = 'test' |
|
78 |
- db.db_add_action(action_id, lat, lon, user_id, action_success) |
|
79 |
- return { |
|
80 |
- 'node': (lat, lon), |
|
81 |
- 'rain': rain, |
|
82 |
- }, 200 |
|
83 |
+ image_arnn['x'].cpu() |
|
84 |
+ del image_arnn |
|
85 |
+ |
|
86 |
+ result = result.to("cpu") |
|
87 |
+ _, predicted = torch.max(result.data, 1) |
|
88 |
+ del result |
|
89 |
+ if predicted == 0: |
|
90 |
+ rain = False |
|
91 |
+ else: # elif result == 1 |
|
92 |
+ rain = True |
|
93 |
+ user_id = 'test' |
|
94 |
+ action_success = True |
|
95 |
+ action_id = 'test' |
|
96 |
+ db.db_add_action(action_id, lat, lon, user_id, action_success) |
|
97 |
+ return { |
|
98 |
+ 'node': (lat, lon), |
|
99 |
+ 'rain': rain, |
|
100 |
+ }, 200 |
|
83 | 101 |
|
84 | 102 |
|
85 | 103 |
@Action.route('/action_display') |
--- app.py
+++ app.py
... | ... | @@ -1,12 +1,10 @@ |
1 |
-from flask import Flask |
|
1 |
+import flask |
|
2 | 2 |
from flask_restx import Api |
3 | 3 |
from auth import Auth |
4 | 4 |
from action import Action |
5 | 5 |
|
6 |
-app = Flask(__name__) |
|
6 |
+app = flask.Flask(__name__) |
|
7 | 7 |
|
8 |
- |
|
9 |
-print("Api Start") |
|
10 | 8 |
api = Api( app, |
11 | 9 |
version='0.1', |
12 | 10 |
title="RDS", |
... | ... | @@ -15,10 +13,7 @@ |
15 | 13 |
contact="[email protected]", |
16 | 14 |
license="MIT") |
17 | 15 |
|
18 |
- |
|
19 |
- |
|
20 | 16 |
api.add_namespace(Auth, '/auth') |
21 |
-print("Api Add Auth") |
|
22 | 17 |
|
23 | 18 |
api.add_namespace(Action, '/action') |
24 | 19 |
|
+++ asset/rain-svgrepo-com.png
Binary file is not shown |
+++ asset/sun-svgrepo-com.png
Binary file is not shown |
--- auth.py
+++ auth.py
... | ... | @@ -1,5 +1,5 @@ |
1 | 1 |
import hashlib |
2 |
-from flask import request, jsonify, render_template,redirect,url_for |
|
2 |
+from flask import request, jsonify |
|
3 | 3 |
from flask_restx import Resource, Api, Namespace, fields |
4 | 4 |
from database.database import DB |
5 | 5 |
import datetime |
+++ demonstration.py
... | ... | @@ -0,0 +1,107 @@ |
1 | +import random | |
2 | +import time | |
3 | +import visdom | |
4 | +import glob | |
5 | +import torch | |
6 | +import cv2 | |
7 | +from torchvision.transforms import ToTensor, Compose, Normalize | |
8 | +from flask import request | |
9 | +from model.AttentiveRNN import AttentiveRNN | |
10 | +from model.Classifier import Resnet as Classifier | |
11 | +from subfuction.image_crop import crop_image | |
12 | + | |
13 | +device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
14 | + | |
15 | +# execute visdom instance first | |
16 | +# to do that, install visdom via pip and execute in terminal | |
17 | + | |
18 | +def process_image(): | |
19 | + vis = visdom.Visdom() | |
20 | + arnn = AttentiveRNN(6, 3, 2) | |
21 | + arnn.load_state_dict(torch.load("weights/ARNN_trained_weight_6_3_2.pt")) | |
22 | + arnn.to(device=device) | |
23 | + arnn.eval() | |
24 | + crop_size = (512, 512) | |
25 | + start_point = (750, 450) | |
26 | + tf_toTensor = ToTensor() | |
27 | + classifier = Classifier(in_ch=1) | |
28 | + classifier.load_state_dict(torch.load("weights/classifier_e19_weight_1080p_512512_fixed_wrong_resolution_and_ch.pt")) | |
29 | + classifier.to(device=device) | |
30 | + classifier.eval() | |
31 | + rainy_data_path = glob.glob("/home/takensoft/Pictures/화창한날, 비오는날 프레임2000장/SUNNY/**/**/*.png") | |
32 | + # rainy_data_path = glob.glob("/home/takensoft/Pictures/폭우 빗방울 (475개)/*.png") | |
33 | + img_path = rainy_data_path | |
34 | + # clean_data_path = glob.glob("/home/takensoft/Documents/AttentiveRNNClassifier/output/original/*.png") | |
35 | + | |
36 | + # img_path = rainy_data_path + clean_data_path | |
37 | + # normalize = Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) | |
38 | + random.shuffle(img_path) | |
39 | + | |
40 | + for i in iter(range(len(img_path))): | |
41 | + image = crop_image(img_path[i], crop_size, start_point) | |
42 | + if not image.any(): | |
43 | + continue | |
44 | + image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | |
45 | + image_tensor = tf_toTensor(image) | |
46 | + image_tensor = image_tensor.unsqueeze(0) | |
47 | + image_tensor = image_tensor.to(device) | |
48 | + image_arnn = arnn(image_tensor) | |
49 | + | |
50 | + input_win = 'input_window' | |
51 | + attention_map_wins = [f'attention_map_{i}' for i in range(6)] | |
52 | + prediction_win = 'prediction_window' | |
53 | + | |
54 | + # Visualize attention maps using visdom | |
55 | + vis.images( | |
56 | + image_tensor, | |
57 | + opts=dict(title=f"input"), | |
58 | + win=input_win | |
59 | + ) | |
60 | + for idx, attention_map in enumerate(image_arnn['attention_map_list']): | |
61 | + if idx == 0 or idx == 5: | |
62 | + vis.images( | |
63 | + attention_map.cpu(), # Expected shape: (batch_size, C, H, W) | |
64 | + opts=dict(title=f'Attention Map {idx + 1}'), | |
65 | + win=attention_map_wins[idx] | |
66 | + ) | |
67 | + # arnn_result = normalize(image_arnn['x']) | |
68 | + result = classifier(image_arnn['attention_map_list'][-1]) | |
69 | + result = result.to("cpu") | |
70 | + _, predicted = torch.max(result.data, 1) | |
71 | + print(result.data) | |
72 | + print(_) | |
73 | + print(predicted) | |
74 | + # Load and display the corresponding icon | |
75 | + if predicted == 0: | |
76 | + icon_path = 'asset/sun-svgrepo-com.png' | |
77 | + else: # elif result == 1 | |
78 | + icon_path = 'asset/rain-svgrepo-com.png' | |
79 | + | |
80 | + # Load icon and convert to tensor | |
81 | + icon_image = cv2.imread(icon_path, cv2.IMREAD_UNCHANGED) | |
82 | + transform = Compose([ | |
83 | + ToTensor() | |
84 | + ]) | |
85 | + icon_tensor = transform(icon_image).unsqueeze(0) # Add batch dimension | |
86 | + | |
87 | + # Visualize icon using visdom | |
88 | + vis.images( | |
89 | + icon_tensor, | |
90 | + opts=dict(title='Weather Prediction'), | |
91 | + win=prediction_win | |
92 | + ) | |
93 | + time.sleep(1) | |
94 | + | |
95 | + # result = classifier(image_arnn['x']) | |
96 | + # result = result.to("cpu") | |
97 | + # _, predicted = torch.max(result.data, 1) | |
98 | + # if predicted == 0: | |
99 | + # rain = False | |
100 | + # else: # elif result == 1 | |
101 | + # rain = True | |
102 | + # return { | |
103 | + # 'rain': rain, | |
104 | + # }, 200 | |
105 | + | |
106 | +if __name__ == "__main__": | |
107 | + process_image()(파일 끝에 줄바꿈 문자 없음) |
--- model/AttentiveRNN.py
+++ model/AttentiveRNN.py
... | ... | @@ -217,8 +217,8 @@ |
217 | 217 |
lstm_feats.append(lstm_feats_i) |
218 | 218 |
ret = { |
219 | 219 |
'x' : x, |
220 |
- 'attention_map_list' : attention_map, |
|
221 |
- 'lstm_feats' : lstm_feats |
|
220 |
+ # 'attention_map_list' : attention_map, |
|
221 |
+ # 'lstm_feats' : lstm_feats |
|
222 | 222 |
} |
223 | 223 |
return ret |
224 | 224 |
|
--- requirements.txt
... | ... | @@ -1,11 +0,0 @@ |
1 | -torch~=2.0.1+cu118 | |
2 | -flask~=2.3.3 | |
3 | -jwt~=1.3.1 | |
4 | -werkzeug~=2.3.7 | |
5 | -torchvision~=0.15.2+cu118 | |
6 | -networkx~=3.0 | |
7 | -geojson~=3.0.1 | |
8 | -haversine~=2.8.0 | |
9 | -opencv-python~=4.8.0.76 | |
10 | -joblib~=1.3.2 | |
11 | -pandas~=2.0.3(파일 끝에 줄바꿈 문자 없음) |
--- subfuction/image_crop.py
+++ subfuction/image_crop.py
... | ... | @@ -1,14 +1,12 @@ |
1 | 1 |
import cv2 |
2 | 2 |
import os |
3 | 3 |
|
4 |
-def crop_image(image_path, crop_size, start_point): |
|
5 |
- if image_path.endswith(".jpg") or image_path.endswith(".png"): |
|
6 |
- image = cv2.imread(image_path) |
|
7 |
- height, width = image.shape[:2] |
|
4 |
+def crop_image(image, crop_size, start_point): |
|
5 |
+ height, width = image.shape[:2] |
|
8 | 6 |
|
9 |
- if width > start_point[0] + crop_size[0] and height > start_point[1] + crop_size[1]: |
|
10 |
- cropped_image = image[start_point[1]:start_point[1]+crop_size[1], start_point[0]:start_point[0]+crop_size[0]] |
|
11 |
- return cropped_image |
|
12 |
- else: |
|
13 |
- print(f"Image {os.path.basename(image_path)} is too small to be cropped with the current settings.") |
|
14 |
- return False(파일 끝에 줄바꿈 문자 없음) |
|
7 |
+ if width > start_point[0] + crop_size[0] and height > start_point[1] + crop_size[1]: |
|
8 |
+ cropped_image = image[start_point[1]:start_point[1]+crop_size[1], start_point[0]:start_point[0]+crop_size[0]] |
|
9 |
+ return cropped_image |
|
10 |
+ else: |
|
11 |
+ print(f"Image is too small to be cropped with the current settings.") |
|
12 |
+ return False(파일 끝에 줄바꿈 문자 없음) |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?