Skip to content

Commit

Permalink
chore : cctv 수정
Browse files Browse the repository at this point in the history
chore : cctv 수정
  • Loading branch information
begong313 authored May 22, 2024
2 parents c35451f + 350d781 commit 29e4eb4
Show file tree
Hide file tree
Showing 23 changed files with 212 additions and 52 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ aiServer/crowdhuman_yolov5m.pt
ai/.env
frontend/.env
server/src/main/java/com/capstone/server/dataInitializer/CCTVInitializer.java

/ai/TextReID/datasets/imgs
ai/imageSearch/results.json
ai/imageSearch/search_result_grid.jpg
1 change: 0 additions & 1 deletion ai/TextReID/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*.npy

output/
datasets/
pretrained/
__pycache__/
condor_log/
Expand Down
5 changes: 3 additions & 2 deletions ai/TextReID/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ python train_net.py \
python3 test_net.py \
--config-file configs/cuhkpedes/moco_gru_cliprn50_ls_bs128_2048.yaml \
--checkpoint-file output/cuhkpedes/moco_gru_cliprn50_ls_bs128_2048/best.pth \
--data-dir datasets/cuhkpedes \
--query "a man wearing a white black top and white pants"
--data-dir /home/jongbin/Desktop/yolo/58 \
--query "a boy has short hair. he wearing a white short sleeve and a khaki a long pants"

# 코드 안에서 QUERY를 받게 바꿨음
```

Expand Down

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions ai/TextReID/lib/data/datasets/cuhkpedes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import json
import os

import torch
from PIL import Image

from lib.utils.caption import Caption


class CUHKPEDESDataset(torch.utils.data.Dataset):
def __init__(
self,
root,
ann_file,
use_onehot=True,
max_length=100,
transforms=None,
):
self.root = root
self.use_onehot = use_onehot
self.max_length = max_length
self.transforms = transforms

self.img_dir = os.path.join(self.root, "imgs")
# self.img_dir = self.root

print("loading annotations into memory...")
dataset = json.load(open(ann_file, "r"))
self.dataset = dataset["annotations"]

def __getitem__(self, index):
"""
Args:
index(int): Index
Returns:
tuple: (images, labels, captions)
"""
data = self.dataset[index]

img_path = data["file_path"]
img = Image.open(os.path.join(self.img_dir, img_path)).convert("RGB")

if self.use_onehot:
caption = data["onehot"]
caption = torch.tensor(caption)
caption = Caption([caption], max_length=self.max_length, padded=False)
else:
caption = data["sentence"]
caption = Caption(caption)

caption.add_field("img_path", img_path)

label = int(data["id"])

# Convert label to string representation and then to tensor of ASCII values
label_str = str(label)
label_tensor = torch.tensor([ord(char) for char in label_str])
caption.add_field("id", label_tensor)

if self.transforms is not None:
img = self.transforms(img)

query = data["sentence"]

return img, caption, index, query

def __len__(self):
return len(self.dataset)

def get_id_info(self, index):
image_id = self.dataset[index]["image_id"]
pid = self.dataset[index]["id"]
return image_id, pid
27 changes: 14 additions & 13 deletions ai/TextReID/lib/data/metrics/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def evaluation(
save_data=True,
rerank=True,
search_num=0,
save_folder = "./output/output.json"
save_folder="./output/output.json"
):
logger = logging.getLogger("PersonSearch.inference")
data_dir = os.path.join(output_folder, "inference_data.npz")
Expand All @@ -103,20 +103,26 @@ def evaluation(
image_ids, pids = [], []
image_global, text_global = [], []

# FIXME: need optimization
for idx, prediction in predictions.items():
image_id, pid = dataset.get_id_info(idx)
image_ids.append(image_id)
pids.append(pid)
image_global.append(prediction[0])
if len(prediction) == 2:
# text query를 하나만 넣었으므로, text emgedding은 배치의 제일 처음 이미지에만 들어감
# 왜냐하면 유사도 검사 시 배치 별로 검사를 했으니까
text_global.append(prediction[1])

pids = list(map(int, pids))
image_pid = torch.tensor(pids)
text_pid = torch.tensor(pids)
# Convert pids to string representation and then to tensor of ASCII values
pids = list(map(str, pids))
pids = [torch.tensor([ord(char) for char in pid]) for pid in pids]

# Find the maximum length of pids
max_length = max(len(pid) for pid in pids)

# Pad all pids to the same length
pids = [F.pad(pid, (0, max_length - len(pid)), value=0) for pid in pids]

image_pid = torch.stack(pids)
text_pid = torch.stack(pids)
image_global = torch.stack(image_global, dim=0)
text_global = torch.stack(text_global, dim=0)

Expand All @@ -129,21 +135,16 @@ def evaluation(

similarity = torch.matmul(text_global, image_global.t())

# top 10 results 반환
sorted_indices = torch.argsort(similarity[0], descending=True)
sorted_values = similarity[0][sorted_indices]
top_k = cfg.TEST.TOP_K
write = [cap[0]] # 저장할 output
write = [cap[0]]
for index, value in zip(sorted_indices[:top_k], sorted_values[:top_k]):
# image_id, pid = dataset.get_id_info(idx)
img, caption, idx, query = dataset.__getitem__(index)
img_path = caption.get_field("img_path")
# print(f"Index: {index}, Similarity: {value}, pid: {pid}")
dict = {"img_path": img_path, "Similarity": value.item()}
write.append(dict)


#저장 폴더 생성
if not os.path.exists(os.path.dirname(save_folder)):
os.makedirs(os.path.dirname(save_folder), exist_ok=True)

Expand Down
2 changes: 1 addition & 1 deletion ai/TextReID/test_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def main():
)
parser.add_argument(
"--top-k",
default=10,
default=400,
type=int,
)

Expand Down
46 changes: 36 additions & 10 deletions ai/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
sys.path.append(str(Path(__file__).parent)+"/yolov8")
sys.path.append(str(Path(__file__).parent)+"/TextReID")
sys.path.append(str(Path(__file__).parent)+"/imageSearch")

import shutil
from TextReID.test_net import findByText
from yolov5_crowdhuman.detect import run_detection
from yolov8.run import run_Yolo
Expand Down Expand Up @@ -92,20 +92,35 @@ async def firstDetection(input :TotalInput):
raise HTTPException(status_code=400, detail="cctv is undefined")
yolo_save_path = f"/home/jongbin/Desktop/yolo/{input.searchId}" #경로는 각자 환경에 맞게 조장하시오
run_Yolo(input.cctvId,yolo_save_path,input.startTime) #todo start time 따라 input다르게 만들기
# run_Yolo(input.cctvId,yolo_save_path,"2024-05-24T01:01:01") #todo start time 따라 input다르게 만들기
result_dir = await runTextReID(input, yolo_save_path) #text-re-id돌리고 결과 json파일 받아오기
with open(result_dir, 'r') as json_file:
data = json.load(json_file)
image_paths = [entry['img_path'] for entry in data if 'img_path' in entry]
destination_folder = f'/home/jongbin/Desktop/firstResult/{input.searchId}'
os.makedirs(destination_folder, exist_ok=True)
# 이미지 복사
for img_path in image_paths:
if os.path.exists(img_path):
shutil.copy(img_path, destination_folder)

result_json_dir = await uploadS3(result_dir,input.missingPeopleId, input.searchId, input.step) #json파일로 결과들 s3업로드하고 서버로 보낼 데이터 모음 json받아오기
with open(result_json_dir, 'r') as file:
result = json.load(file)

return DetectResult(searchId= input.searchId, missingPeopleId= input.missingPeopleId, data = result[1:])
# 이미지 경로 리스트


return DetectResult(searchId= input.searchId, missingPeopleId= input.missingPeopleId, data = result[1:16])

#2차탐색
@app.post("/second", response_model=DetectResult)
async def secondDetection(input:SecondInput):
print(input)
img_download_url = "/home/jongbin/Desktop/imgDown"
data_path = f"/home/jongbin/Desktop/yolo/{input.firstSearchId}"
data_path = f"/home/jongbin/Desktop/firstResult/{input.firstSearchId}"
result = []
check = set()
for img_path in input.queryImagePath:
#img_path는 s3주소 특정폴더에 다운로드하고 경로가져오기
local_image_path = os.path.join(img_download_url, os.path.basename(img_path))
Expand All @@ -115,14 +130,19 @@ async def secondDetection(input:SecondInput):
for output in data_to_save['output']:
#해당 주소에 있는 이미지 s3업로드하고 이미지 주소 result에 넣기
local_output_path = output['output_dir']
if local_output_path in check:
continue
check.add(local_output_path)
new_file_name = f"{os.path.basename(local_output_path).split('.')[0]}"
new_file_name = new_file_name.replace(' ', '-').replace(':', '').replace('/', '+')
s3_key = f"missingPeopleId={input.missingPeopleId}/searchHistoryId={input.secondSearchId}/step=second/{new_file_name}"
s3_url = upload_image_to_s3(local_output_path, s3_key)
a = {"img_path" : s3_url, "cctvId" : new_file_name.split('_')[0], "similarity" :output['score'] } #todo : 버그수정
a = {"img_path" : s3_url, "cctvId" : new_file_name.split('_')[0], "similarity" :(10000-output['score'])/10000 }
# a = {"img_path" : s3_url, "cctvId" : new_file_name.split('_')[0], "similarity" :output['score']}
result.append(a)

result = sorted(result,key = lambda x:x["score"])
result = sorted(result,key = lambda x:x["similarity"])
print(result)
return DetectResult(searchId= input.secondSearchId, missingPeopleId= 1, data = result)

async def runTextReID(input : TotalInput, yolo_save_path:str):
Expand All @@ -132,7 +152,7 @@ async def runTextReID(input : TotalInput, yolo_save_path:str):
home_path = os.path.expanduser("~")
result_dir = os.path.join(home_path, "Desktop", "result", str(input.searchId) ,"output.json")
# findByText(root_path, search_num=input.searchId, query = input.query, data_dir = yolo_save_path, save_folder = result_dir)
findByText(root_path, search_num=input.searchId, query = input.query, data_dir = yolo_save_path, save_folder = result_dir)
findByText(root_path, search_num=input.searchId, query = input.query, data_dir = yolo_save_path, save_folder = result_dir,result_num=200)
return result_dir


Expand All @@ -146,7 +166,7 @@ async def uploadS3(json_file_path:str, missingPeopleId:int, searchId:int, step:s
# 이미지 파일을 S3에 업로드하고 URL 업데이트
errors = []
# 리스트의 첫 번째 요소는 무시하고 나머지에서 작업 수행
for item in data[1:]:
for item in data[1:16]:
img_path = item['img_path']
similarity = item['Similarity']
new_file_name = f"{os.path.basename(img_path).split('.')[0]}_{similarity}{os.path.splitext(img_path)[-1]}"
Expand Down Expand Up @@ -208,7 +228,13 @@ def upload_image_to_s3(local_path, s3_key):
"""
로컬 경로의 이미지를 S3 버킷의 지정된 키에 업로드합니다.
"""
s3_client.upload_file(local_path, bucket_name, s3_key,ExtraArgs={
'ACL': 'public-read' # 원하는 ACL 권한으로 설정
})
with open(local_path, 'rb') as img_file:
s3_client.upload_fileobj(
Fileobj=img_file,
Bucket=bucket_name,
Key=s3_key,
ExtraArgs={
'ACL': 'public-read' # 공개적으로 읽을 수 있도록 권한 설정
})

return f"https://{bucket_name}.s3.amazonaws.com/{s3_key}"
30 changes: 30 additions & 0 deletions ai/forTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import json
import os
import shutil

# JSON 파일 경로
json_file_path = '/home/jongbin/Documents/GitHub/capstone-2024-14/capstone-2024-14/ai/TextReID/output/output.json'

# 이미지를 복사할 대상 폴더 경로
destination_folder = '/home/jongbin/Desktop/copied_images'

# 대상 폴더가 존재하지 않으면 생성
if not os.path.exists(destination_folder):
os.makedirs(destination_folder)

# JSON 파일 읽기
with open(json_file_path, 'r') as json_file:
data = json.load(json_file)

# 이미지 경로 리스트
image_paths = [entry['img_path'] for entry in data if 'img_path' in entry]

# 이미지 복사
for img_path in image_paths:
if os.path.exists(img_path):
shutil.copy(img_path, destination_folder)
print(f"Copied: {img_path}")
else:
print(f"File not found: {img_path}")

print("Image copying completed.")
2 changes: 1 addition & 1 deletion ai/imageSearch/imgSearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def save_results(query_image_path, scores, retrieved_examples, sorted_indices):

# ===== 결과 저장
scores, retrieved_examples = get_neighbors(args.query, args.topk)
sorted_indices = np.argsort(scores)[::-1]
sorted_indices = np.argsort(scores)[::]

images = [Image.open(args.query)]
images.extend([Image.open(retrieved_examples["image_path"][i]) for i in sorted_indices])
Expand Down
8 changes: 4 additions & 4 deletions ai/imageSearch/imgSearch_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ def run_Image_to_Image(data_path:str,topk:int,query:str):
dataset.add_faiss_index(column='embeddings')
# ===== 결과 저장
scores, retrieved_examples = get_neighbors(query, dataset, topk)

sorted_indices = np.argsort(scores)[::]

sec = time.time() - start_time
times = str(datetime.timedelta(seconds=sec))
short = times.split(".")[0]
print(f"The 2nd search has ended. \nThe time required: {short} sec\n")
return save_results(query, scores, retrieved_examples)
return save_results(query, scores, retrieved_examples,sorted_indices)

# ===== 사전학습 모델 세팅 및 특징 추출기 세팅
def load_image_paths(data_dir):
Expand Down Expand Up @@ -96,12 +96,12 @@ def default(o):
if isinstance(o, np.float32):
return float(o)

def save_results(query_image_path, scores, retrieved_examples):
def save_results(query_image_path, scores, retrieved_examples,sorted_indices):
data_to_save = {
"query_dir": query_image_path,
"output": [
{"output_dir": retrieved_examples['image_path'][i], "score": float(scores[i])}
for i in range(len(scores))
for i in sorted_indices
]
}
return data_to_save
Expand Down
4 changes: 3 additions & 1 deletion ai/imageSearch/readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
python3 imgSearch.py --data_path /home/jongbin/Desktop/yolo/164 --topk 20 --query /home/jongbin/Desktop/yolo/164/1_2024-05-14_16-07-56_155.jpg
python3 imgSearch.py --data_path /home/jongbin/Desktop/copied_images --topk 20 --query /home/jongbin/Desktop/copied_images/5_2024-05-14_16-26-33_133.jpg

python3 imgSearch.py --data_path /home/jongbin/Desktop/yolo/23 --topk 40 --query /home/jongbin/Desktop/copied_images/1_2024-05-14_16-07-56_387.jpg

/home/jongbin/Desktop/yolo/164
2 changes: 2 additions & 0 deletions ai/yolov8/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ def run_Yolo(cctvIds,save_path,startTime):
annotations = []
for cctv_id in cctvIds:
source_path = f'/home/jongbin/Desktop/cctv/{cctv_id.id}/{startTime.split("T")[0]}' #todo 세부적인 시 분 초 시간까지 골라서 돌리기 기능 추가
if not os.path.exists(source_path):
continue # source_path가 존재하지 않으면 다음 반복으로 넘어감
for filename in os.listdir(source_path):
source = os.path.join(source_path, filename)
start_time = extract_video_info(filename)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@

import com.capstone.server.dto.CCTVDto;
import com.capstone.server.model.CCTVEntity;
import com.capstone.server.model.CCTVEntity;
import com.capstone.server.repository.CCTVRepository;
import com.capstone.server.response.SuccessResponse;
import com.capstone.server.service.CCTVService;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.transaction.Transactional;

Expand All @@ -30,10 +33,10 @@ public class CCTVController {

@GetMapping
public ResponseEntity<?> getAllCCTV(
@RequestParam(required = true, value = "longitude") double longitude,
@RequestParam(required = true, value = "latitude") double latitude,
@RequestParam(required = false, defaultValue = "1000", value = "distance") double distance) {
@RequestParam(required = true, value = "longitude") double longitude,
@RequestParam(required = true, value = "latitude") double latitude,
@RequestParam(required = false, defaultValue = "1000", value = "distance") double distance) {

List<CCTVDto> CCTVList = cctvService.findCCTVsNearbyLocationWithinDistance(longitude, latitude);
return ResponseEntity.ok().body(CCTVList);
}
Expand Down
Loading

0 comments on commit 29e4eb4

Please sign in to comment.