<repo_name>yester31/useful_code<file_sep>/18. visualize coco format dataset/visual_sample.py
import json
import cv2
import numpy as np
from PIL import ImageFont, ImageDraw, Image

# red , blue, green
color_map = [(0, 0, 255), (255, 0, 0), (0, 255, 0), (0, 255, 255), (255, 0, 255), (255, 255, 255),
             (0, 0, 127), (127, 0, 0), (0, 127, 0), (0, 127, 127), (127, 0, 127), (127, 127, 127),
             (0, 127, 255), (255, 127, 0)]

if __name__ == "__main__":

    dataset_label_path = 'D:/dataset/coco2017/annotations/instances_val2017.json'
    with open(dataset_label_path, 'rt', encoding='UTF-8') as annotations:
        coco = json.load(annotations)
        images = coco['images']
        annotations = coco['annotations']
        categories = coco['categories']

        categ_dict = {}
        for c_idx, categ in enumerate(categories):
            categ_dict[categ["id"]] = categ["name"]

        for i_idx, img in enumerate(images):
            img_path = 'D:/dataset/coco2017/val2017/' + img['file_name']

            # numpy 를 이용 하여 이미지 데이터 로드 (경로에 만약 한글이 포함 되어 있다면, cv2.imread()에서 파일을 못 읽음)
            img_array = np.fromfile(img_path, np.uint8)
            image = cv2.imdecode(img_array, cv2.IMREAD_COLOR)

            for a_idx, anno in enumerate(annotations):
                if img['id'] == anno['image_id']:
                    bbox = anno['bbox']
                    seg = anno['segmentation']
                    color = color_map[anno['category_id'] % len(color_map)]

                    # PIL을 통하여 이미지에 한글 출력 (cv2.putText()에서 한글 출력 못 함, 빌드 새로 해야함..)
                    pimg = Image.fromarray(image)  # img 배열을 PIL이 처리 가능 하게 변환
                    name = categ_dict[anno['category_id']]  # 해당 category_id의 이름 가져오기
                    ImageDraw.Draw(pimg).text((bbox[0] + 5, bbox[1] + 10), name,
                                              font=ImageFont.truetype("fonts/gulim.ttc", 20),
                                              fill=color)  # 해당 라벨의 이름을 출력

                    # bounding box 출력
                    image = cv2.rectangle(np.array(pimg), (int(bbox[0]), int(bbox[1])),
                                          (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])),
                                          color, 1)
                    # polygon 출력
                    if str(type(seg)) == '<class \'list\'>':
                        for pp_idx in range(len(seg)):
                            for p_idx in range(int(len(seg[pp_idx]) / 2)):
                                image = cv2.circle(image,
                                                   (int(seg[pp_idx][p_idx * 2]), int(seg[pp_idx][p_idx * 2 + 1])), 2,
                                                   color, -1)

            cv2.imshow('results', image)
            if cv2.waitKey() == 27:
                cv2.destroyWindow("results")
                break

        print("done")
<file_sep>/04. simple websocket server node-express/app.js
"use strict";
const express = require('express'); // express라이브러리 호출
const app = express();              // express 객체 생성
const webMonitoringPort = 8080;     // websocket test page web server port
const webSocketPort = 8000;         // websocket server port
const fs = require('fs');     // 파일 처리 관련 라이브러리
const ejs = require('ejs');   // html파일에 JavaScript를 내장하여 서버에서 보낸 변수를 사용할 수 있음. 
const path = require('path'); // 경로 관련 라이브러리
// 정적(static) 경로 설정
app.use(express.static(path.join(__dirname,'public'))); // public 폴더 내에 있는 파일들은 브라우저에서 접근 가능
app.use(express.static('public'));

// 예제로 만든 api client에서 /test로 호출하면 test.html 파일과 tt 변수를 리턴함.
app.get('/', (req, res) => {  
  fs.readFile('view/client.html', 'utf-8', function (error, data) {
    if(error) {
      console.log(error) 
      return;
    } else {
      let tt = 'text from sever'
      res.send(
        ejs.render(
          data, {text : tt}
        )
      );
    }
  })
})
// 에러 처리 부분
app.use(function(req, res, next) {
  res.status(404).send('Sorry cant find that!');
});
app.use(function (err, req, res, next) {
  if(err){
    console.error(err.stack);
    console.log("error!!!!");
    res.status(500).send('Something broke!');
  }
});

app.listen(webMonitoringPort, () => {
	console.log(`web server listening at : ${webMonitoringPort}`);
}); 

// 웹소켓 서버 
const webSocket = require('./webSocketServer');
const server = app.listen(webSocketPort, () => {
    console.log(`websocket server listening at : ${webSocketPort}`);
});

webSocket(server);<file_sep>/13. show deep learning result on Web Browser/server/public/webSocketClient.js
'use strict';

const wsid = '2'
const wstype = 'webc'
const url = 'ws://localhost:8000'
const wsk = new WebSocket(`${url}/wsid=${wsid}&wstype=${wstype}`); // ws

wsk.onopen = function () {
    console.log('서버와 웹 소켓 연결됨');
    wsk.send(JSON.stringify({
      optype: "init_websocket",   // optype    : 동작 유형(init_websocket 클라이언트에서 연결 완료 후 서버로 확인 메시지 전달)
      wsid:   wsid,               // wsid      : 해당 소켓 아이디
      wstype: wstype,             // wstype    : 소켓 접속 유형
      msg : "Hello Server ? I am web client!!", // msg       : 메시지
      timestamp: timestamp()      // timestamp : 현재 시간
    }));
};

wsk.onmessage = function (event) {
  let msgjson = JSON.parse(event.data);
  switch (msgjson.optype) {	
    case 'output': // python으로부터 이미지 수신
      let imaget = "data:image/jpg;base64," + msgjson.frame;  // img tag의 소스로 전달하기 위해 frame 정보에 헤더를 붙임
      document.getElementById("myimage").src = imaget;        // (4) 화면에 출력
      break;
    default:
      console.log('optype error : ' + msgjson.optype)
      break;
  }
}

wsk.onclose = function () {
    console.log("disconnected websocket")
}

<file_sep>/12. image from browser to local with ws/websocket client py/client.py
import asyncio
import websockets
import cv2
import base64
import numpy as np
import json
from datetime import datetime

def timestamp() :
    return datetime.now().strftime('%Y-%m-%d %H:%M:%S')

async def connect(ip, port, wsid, wstype):

    # 웹 소켓에 접속
    async with websockets.connect("ws://{}:{}/wsid={}&wstype={}".format(ip, port,wsid, wstype)) as websocket:
        try:
            if websocket.open == True:
                init_websocket_msg = {
                    'optype': 'init_websocket',
                    'wsid': wsid,
                    'wstype': wstype,
                    'msg': 'Hello Server ? I am py',
                    'timestamp': timestamp()
                }
                jsonString = json.dumps(init_websocket_msg) # json 객체를 인코딩하여 string으로 만듬
                await websocket.send(jsonString)

            # 전달 받은 base64로 인코딩된 frame을 이미지로 변환하여 opencv로 영상 형태로 출력
            while 1 :
                data = await websocket.recv()
                jsonObject = json.loads(data) # json 디코딩 (string 형태의 데이터를 json 객체로 만듬)
                optype = jsonObject.get("optype") # dic 데이터 형식으로 호출

                if optype == "input":
                    raw_frame = jsonObject.get("frame")
                    step1 = str(raw_frame.split(',')[1])
                    step2 = base64.b64decode(step1)
                    step5 = np.frombuffer(step2, np.uint8)
                    frame = cv2.imdecode(step5, cv2.IMREAD_COLOR)
                    cv2.imshow('(3) python_code', frame)

                    if cv2.waitKey(1) & 0xFF == ord('q'):
                        break

                    encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 100]
                    result, encimg = cv2.imencode('.jpg', frame, encode_param)
                    if False == result:
                        print('could not encode image!')

                    # 이미지를 String 형태로 변환(인코딩)시키는 과정
                    encoded_output = base64.b64encode(encimg).decode('utf-8')
                    output_msg = {
                        'optype': 'output',
                        'wsid': wsid,
                        'wstype': wstype,
                        'frame': encoded_output,
                        'timestamp': timestamp()
                    }
                    jsonString = json.dumps(output_msg) # json 객체를 인코딩하여 string으로 만듬
                    await websocket.send(jsonString)

                else:
                    print("[ERROR]  메시지 : {}".format(data))

            # python client 코드에서 웹소켓을 통해 영상을 전달하는 로직
            '''
            capture = cv2.VideoCapture(0)  # 웹캠
            while 0 :
                ret, frame = capture.read()
                frame = cv2.resize(frame, dsize=(350, 260), interpolation=cv2.INTER_AREA)
                encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 100]
                result, encimg = cv2.imencode('.jpg', frame, encode_param)
                if False == result:
                    print('could not encode image!')

                # 이미지를 String 형태로 변환(인코딩)시키는 과정
                encoded = base64.b64encode(encimg).decode('utf-8')
                input_msg = {
                    'optype': 'output',
                    'wsid': wsid,
                    'wstype': wstype,
                    'frame': encoded,
                    'timestamp': timestamp()
                }
                jsonString = json.dumps(input_msg)  # json 객체를 인코딩하여 string으로 만듬
                await websocket.send(jsonString)
            '''
        except:
            print("error!!!")
            return 0

if __name__ == "__main__":

    ip = 'localhost'
    port = 8000
    wsid = 1
    wstype = 'pyc'
    asyncio.get_event_loop().run_until_complete(connect(ip, port, wsid, wstype))
    asyncio.get_event_loop().run_forever()
<file_sep>/01. detected objects crop and save/tt.py
# --------------------------------------------------------
# Detected objects Crop and Save by class
# Licensed under The MIT License
# Written by Derek
# 2021-06-26
# --------------------------------------------------------'
import os, cv2, uuid, time
import numpy as np

# deep learning 모델에 결과로 detection된 객체들의 이미지를 파일로 클래스 별로 저장하는 예제 코드
# 각 frame에서 detection된 객체들의 객체 별 box, class id 이용하여 분류 저장

'''
    생성되는 디렉토리 구조 
    - root dir - sub_root_dir - class_name0 - frame0_0_uuid
                                            - frame0_1_uuid
                              - class_name1 - frame0_0_uuid 
                              - class_name2 - frame0_0_uuid 
                                                                              
               - sub_root_dir - class_name1 - frame0_0_uuid
'''

class_name_table = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']

def save_box_img(object_class_lsit, object_box_list, frame_id, frame, video_name, dir_root_path = './dataset') :
    boc = time.time()

    unique_number = str(uuid.uuid1())                       # 유니크 숫자 생성
    if os.path.exists(dir_root_path) is False:              # 이미지를 저장할 최상위 폴더가 없다면
        os.makedirs(dir_root_path)                          # 최상위 폴더 생성
        print('make directory {} is done'.format(dir_root_path))

    dir_sub_root_path = os.path.join(dir_root_path, video_name)  # 해당 영상(video_name)에 대한 이미지를 저장할 폴더 경로
    if os.path.exists(dir_sub_root_path) is False:               # 해당 영상에 대한 폴더가 없다면
        os.makedirs(dir_sub_root_path)                           # 해당 영상에 대한 폴더 생성
        print('make directory {} is done'.format(dir_sub_root_path))

    for oidx, class_id in enumerate(object_class_lsit):                 # 모델에서 찾은 객체 리스트
        class_name = class_name_table[int(class_id)]                    # 해당 객체 클래스 이름
        dir_class_path = os.path.join(dir_sub_root_path , class_name)   # 클래스 폴더 경로
        image_file_name = '{}_{}_{}.jpg'.format(frame_id, oidx, unique_number) # 이미지 파일 이름{프레임 번호}_{해당 프레임 객체 인식번호}_{유니크값}.jpg
        image_file_path = os.path.join(dir_class_path, image_file_name) # 클래스 폴더 경로

        x1, y1 = int(object_box_list[oidx, 0]), int(object_box_list[oidx, 1])
        x2, y2 = int(object_box_list[oidx, 2]), int(object_box_list[oidx, 3])
        croped_object_image = frame[y1:y2,x1:x2] # y1 y2 x1 x2

        if os.path.exists(dir_class_path):                      # 해당 클래스 폴더가 있으면
            cv2.imwrite(image_file_path, croped_object_image)   # 그냥 저장
        else :                                                  # 해당 클래스 폴더가 없으면
            os.makedirs(dir_class_path)                         # 클래스 폴더 생성 후
            print('make directory {} is done'.format(dir_class_path))
            cv2.imwrite(image_file_path, croped_object_image)   # 저장

        print('({}/{}) save file {} is done'.format(oidx,len(object_class_lsit), image_file_path))

    print('====================================================================================')
    print('Detected object image crop and save process is done')
    print('Duration time is {} [sec]'.format(time.time() - boc))
    print('====================================================================================')

if __name__ == "__main__":

    #yolov5s 결과 예시(원본 frame 이미지 사이즈로 리사이즈 및 패딩 처리 후)
    #                    x1            y1           x2          y2           prob       class_id
    pred = np.array([[2.00000e+00, 3.47000e+02, 4.56000e+02, 6.82000e+02, 9.38516e-01, 2.00000e+00],
                    [5.88000e+02, 4.04000e+02, 8.81000e+02, 6.32000e+02, 9.18750e-01, 2.00000e+00],
                    [5.75000e+02, 3.99000e+02, 6.24000e+02, 4.41000e+02, 8.62566e-01, 2.00000e+00],
                    [6.11000e+02, 3.99000e+02, 6.91000e+02, 4.53000e+02, 7.66945e-01, 2.00000e+00],
                    [9.80000e+02, 3.90000e+02, 1.04700e+03, 4.23000e+02, 7.01548e-01, 2.00000e+00],
                    [4.37000e+02, 3.71000e+02, 5.59000e+02, 4.83000e+02, 6.38990e-01, 7.00000e+00],
                    [6.34000e+02, 3.28000e+02, 6.41000e+02, 3.45000e+02, 5.99452e-01, 9.00000e+00],
                    [5.45000e+02, 3.24000e+02, 5.59000e+02, 3.40000e+02, 5.74450e-01, 9.00000e+00],
                    [8.09000e+02, 3.94000e+02, 8.25000e+02, 4.32000e+02, 5.48406e-01, 0.00000e+00],
                    [5.52000e+02, 3.89000e+02, 5.79000e+02, 4.34000e+02, 5.12884e-01, 2.00000e+00],
                    [6.65000e+02, 3.40000e+02, 7.46000e+02, 4.10000e+02, 4.92299e-01, 7.00000e+00],
                    [7.93000e+02, 3.96000e+02, 8.06000e+02, 4.14000e+02, 4.88801e-01, 0.00000e+00],
                    [7.71000e+02, 3.90000e+02, 7.84000e+02, 4.09000e+02, 4.52478e-01, 0.00000e+00],
                    [9.04000e+02, 3.95000e+02, 9.23000e+02, 4.18000e+02, 4.35165e-01, 0.00000e+00],
                    [5.56000e+02, 3.25000e+02, 5.64000e+02, 3.40000e+02, 3.84715e-01, 9.00000e+00],
                    [8.24000e+02, 4.00000e+02, 8.37000e+02, 4.38000e+02, 3.59820e-01, 0.00000e+00],
                    [7.01000e+02, 4.29000e+02, 7.47000e+02, 4.64000e+02, 3.52281e-01, 0.00000e+00],
                    [6.65000e+02, 3.39000e+02, 7.46000e+02, 4.09000e+02, 3.46599e-01, 5.00000e+00],
                    [1.01900e+03, 3.89000e+02, 1.03900e+03, 4.11000e+02, 3.08561e-01, 0.00000e+00],
                    [7.57000e+02, 3.86000e+02, 7.70000e+02, 4.08000e+02, 2.78430e-01, 0.00000e+00],
                    [6.33000e+02, 3.73000e+02, 6.67000e+02, 4.02000e+02, 2.56180e-01, 7.00000e+00]])

    frame = cv2.imread('NY_720x1280.jpg')   # 해당 frame image (예시) NY_720x1280.jpg
    object_class_lsit = pred[:,5]           # class id list
    object_box_list = pred[:,0:4]           # box list (x1 y1 x2 y2)
    video_name = 'video_name'               # 영상 이름 (영상별로 구별하여 저장하고 싶은 경우 사용, 폴더명과 파일명에 포함됨)
    frame_id = 0                            # 해당 프레임 id (몇 번째 frame인지)
    dir_root_path = './dataset'             # 이미지를 저장할 최상위 폴더 경로 선택

    save_box_img(object_class_lsit, object_box_list, frame_id, frame, video_name, dir_root_path)



<file_sep>/03. simple web server node-express/app.js
// --------------------------------------------------------
// Node Express Simple Web Server  
// Licensed under The MIT License
// Written by Derek
// 2021-06-27
// --------------------------------------------------------

"use strict";
const express = require('express'); //express라이브러리 호출
const app = express();        // express 객체 생성
const webPort = 8000;
const fs = require('fs');     // 파일 처리 관련 라이브러리
const ejs = require('ejs');   // html파일에 JavaScript를 내장하여 서버에서 보낸 변수를 사용할 수 있음. 
const path = require('path'); // 경로 관련 라이브러리

// 정적(static) 경로 설정
app.use(express.static(path.join(__dirname,'public'))); // public 폴더 내에 있는 파일들은 브라우저에서 접근 가능

// 예제로 만든 api client에서 /test로 호출하면 test.html 파일과 tt 변수를 리턴함.
app.get('/test', (req, res) => {  
  fs.readFile('public/test.html', 'utf-8', function (error, data) {
    if(error) {
      console.log(error) 
      return;
    } else {
      let tt = 'text from sever'
      res.send(ejs.render(data, {
        text : tt
      }));
    }
  })
})

// 에러 처리 부분
app.use(function(req, res, next) {
  res.status(404).send('Sorry cant find that!');
});

app.use(function (err, req, res, next) {
  if(err){
      console.error(err.stack);
      console.log("error!!!!");
      res.status(500).send('Something broke!');
  }
});

app.listen(webPort, function(){
  console.log(`listening on ${webPort}`)
}); // 객체 맴버 함수 listen(서버띄울 포트번호, 띄운 후 실행할 코드) 서버 열기 <file_sep>/16. produce a data path list file/splite_train_val.py
import os
import glob
import random

'''
3. train & val 나누기 (통합 파일에서 랜덤으로 나누기 or 각 폴더 별 랜덤으로 나누기)
output:
output/train/train.txt
output/train/val.txt
'''

# 해당 리스트 파일에서 클래스별 수 반환
def getClassCount(list_file_path, label):
    print(list_file_path)
    label_count_dict = {}
    for i, v in enumerate(label):
        label_count_dict[v] = 0

    f = open(list_file_path, 'r', encoding='utf-8')
    lines = f.readlines()
    count = 0
    for line in lines:
        count += 1
        label_count_dict[label[int(line.split(',')[-1].strip())]] += 1
    f.close()
    print(label_count_dict)
    print('Total count : {}'.format(count))
    print()
    return label_count_dict, count

def showClassCount(save_path, label):
    for paths in [x for x in glob.iglob(save_path + '/**', recursive=True)]:
        paths = paths.replace('\\', '/')
        if paths.split('.')[-1] == 'txt':
            getClassCount(paths, label)

# tot_train.txt에서 입력한 비율로 train, val 리스트를 랜덤하게 나누기
def spliteDataset1(save_path, train, val):
    if not os.path.exists(save_path + '/train/'):  # 저장할 폴더가 없다면
        os.makedirs(save_path + '/train/')  # 폴더 생성
        print('make directory {} is done'.format(save_path + '/train/'))

    ratio = val / (train+val)
    train_file = open(save_path + '/train/train.txt', 'w', encoding='utf-8')
    val_file = open(save_path + '/train/val.txt', 'w', encoding='utf-8')

    f = open(save_path + '/tot_train/tot_train.txt', 'r', encoding='utf-8')
    data_path_list = f.readlines()
    f.close()
    count = len(data_path_list)

    val_n = int(count * ratio + 0.5)
    train_n = int(count - val_n)

    val_loc = random.sample(range(1, count), val_n)
    val_path = []

    for n in range(val_n):
        val_path.append(data_path_list[val_loc[n]])
    train_path = data_path_list
    for a in range(val_n):
        train_path.remove(val_path[a])

    for i, v in enumerate(train_path):
        train_file.writelines(v)

    for i, v in enumerate(val_path):
        val_file.writelines(v)

    train_file.close()
    val_file.close()

# 차수 별로 (거의)동일하게 val 값 추출
def spliteDataset2(save_path, train, val):
    if not os.path.exists(save_path + '/train/'):  # 저장할 폴더가 없다면
        os.makedirs(save_path + '/train/')  # 폴더 생성
        print('make directory {} is done'.format(save_path + '/train/'))

    train_file = open(save_path + '/train/train.txt', 'w', encoding='utf-8')
    val_file = open(save_path + '/train/val.txt', 'w', encoding='utf-8')
    ratio = val / (train + val)

    for txt in [x for x in glob.iglob(save_path + '/list_file/*.txt')]:
        txt = txt.replace('\\', '/')
        flag = txt.split('/')[-1].split('.')[0].split('_')[-1]
        if flag == 'train':
            f = open(txt, 'r', encoding='utf-8')
            data_path_list = f.readlines()
            f.close()
            count = len(data_path_list)

            val_n = int(count * ratio + 0.5)
            train_n = int(count - val_n)

            val_loc = random.sample(range(1, count), val_n)
            val_path = []

            for n in range(val_n):
                val_path.append(data_path_list[val_loc[n]])
            train_path = data_path_list
            for a in range(val_n):
                train_path.remove(val_path[a])

            for i, v in enumerate(train_path):
                train_file.writelines(v)

            for i, v in enumerate(val_path):
                val_file.writelines(v)

    train_file.close()
    val_file.close()


if __name__ == '__main__':
    label = ['cat', 'dog']
    save_path = 'output'
    #spliteDataset1(save_path, 8, 2)
    spliteDataset2(save_path, 8, 2)
    showClassCount(save_path, label)



<file_sep>/05. simple webRTC using websocket/webSocketServer.js
"use strict";
const funcs = require('./public/libs');  // 커스텀 라이브러리 불러오기
const WebSocket = require('ws');         // 웹소켓 라이브러리
const Hashtable = require('jshashtable');// 해시테이블 라이브러리
const wshashtable = new Hashtable();     // 해시테이블 생성
global.wshashtable = wshashtable;     // 해시테이블 전역 변수화 시키기
const { v4: uuidV4 } = require('uuid');

module.exports = (server) => {
  // 웹소켓 서버 객체 생성
  const wss = new WebSocket.Server({ server });
  // 클라이언트 접속할 경우 그 클라이언트와 연결된 소켓객체(ws) 생성 
  wss.on('connection', (ws, req) => {

    // 웹 소켓 연결 시 클라이언트 정보 수집
    const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    const port = req.headers['x-forwarded-port'] || req.socket.remotePort;
    console.log('새로운 클라이언트 접속', ip);
    // 사전에 약속된 규칙으로 소켓서버 호출하여 변수 생성
    let conuri =  req.url; //wss://192.168.31.26:8000/wsid=1234&wstype=type1 <- 예시 소켓 호출 (로컬에서는 ws)
    let wsid = conuri.replace(/.+wsid=([^&]+).*/,"$1");
    let wstype= conuri.replace(/.+wstype=([^&]+).*/,"$1");

    // 소켓 연결 정보 해시 테이블에 저장
    wshashtable.put(wsid, ws);  
    wshashtable.keys().forEach(key =>{
      console.log("접속중인 소켓 아이디 :: " + key); 
      wshashtable.get(key).send(JSON.stringify({'optype': 'check_ws_num' ,'ws_count': wshashtable.keys().length}))
      console.log(key + " 로 업데이트된 웹소켓 접속수 전달")
    })
    // 클라이언트로부터 메시지 수신 시
    ws.on('message', (fmessage) => {  
      let msgjson = JSON.parse(fmessage); 
      //console.log(msgjson)        
      switch (msgjson.optype) {	

        case 'send_ws_msg':
          console.log("send_ws_msg 요청 :: ")
          wshashtable.keys().forEach(key =>{
            if (key != msgjson.wsid ){
              wshashtable.get(key).send(fmessage)
            }
          })
          break;

        case 'initi_signal': 
          console.log("initi_signal 요청, ws_count ::" + wshashtable.keys().length);
          if(wshashtable.keys().length >= 2){
            ws.send(JSON.stringify({'optype': 'initi_signal' ,'ws_count': wshashtable.keys().length}))
          }  
          break;

        case 'check_ws_num': 
          console.log("check_ws_num 요청, ws_count ::" + wshashtable.keys().length);
          ws.send(JSON.stringify({'optype': 'check_ws_num' ,'ws_count': wshashtable.keys().length}))
          break;

        case 'offer': 
          console.log("offer 요청 :: ")
          //console.log(msgjson.offer);
          wshashtable.keys().forEach(key =>{
            if (key != msgjson.wsid ){
              wshashtable.get(key).send(fmessage)
              console.log(key + " 로 offer 전달")
            }
          })
          break;
        case 'answer': 
          console.log("answer 요청 :: ")
          wshashtable.keys().forEach(key =>{
            if (key != msgjson.wsid ){
              wshashtable.get(key).send(fmessage)
              console.log(key + " 로 answer 전달")
            }          
          })
          break;
        case 'new-ice-candidate': 
          console.log("new-ice-candidate 요청 :: ")
          wshashtable.keys().forEach(key =>{
            if (key != msgjson.wsid ){
              wshashtable.get(key).send(fmessage)
              console.log(key + " 로 new-ice-candidate 전달")
            }          
          })
          break;
        default:
          console.log('optype error : ' + msgjson.optype)
        }
    });

    // 에러시
    ws.on('error', (error) => { 
      console.error(error);
    });

    // 연결 종료 시
    ws.on('close', () => {
      // 해시테이블에서 소켓 정보 제거 및 종료된 소켓 정보 출력
      wshashtable.remove(wsid);
      console.log(`[종료된 소켓 발생] ${funcs.timestamp()}`);   // 현재 시간 출력
      console.log(`[종료된 소켓 정보] 아이디 : ${wsid} / 접속 종류 : ${wstype} / 아이피 : ${ip} / 포트 : ${port}`);
      console.log(`[현재 접속 리스트] : ${wshashtable.keys()}`);
      wshashtable.keys().forEach(key =>{    
        wshashtable.get(key).send(JSON.stringify({'optype': 'check_ws_num' ,'ws_count': wshashtable.keys().length}))
        console.log(key + " 로 업데이트된 웹소켓 접속수 전달")
      })
    });
  });
};<file_sep>/11. simple python websocket server&client/client/client.py
# --------------------------------------------------------
# Simple Websocket Client
# Licensed under The MIT License
# Written by Derek
# 2021-06-27
# --------------------------------------------------------
import asyncio, websockets

'''
    간단한 파이썬 웹소켓 클라이언트 구현
'''

async def connect():

    # 웹 소켓에 접속을 합니다.
    async with websockets.connect("ws://localhost:8000") as websocket:
        # 웹 소켓 서버로 부터 메시지가 오면 콘솔에 출력
        while True :
            client_msg = input('> [client] ')
            await websocket.send(client_msg)

            server_msg = await websocket.recv()
            print('< [server] {}'.format(server_msg))

asyncio.get_event_loop().run_until_complete(connect())<file_sep>/20. ensemble/ensemble.py
import os, json, time
import pandas as pd
import numpy as np
from ensemble_boxes import *
from tqdm import tqdm
from pycocotools.coco import COCO
from pycocotools.cocoeval import COCOeval

id_matching = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 28, 31, 32,
               33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
               60, 61, 62, 63, 64, 65, 67, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84, 85, 86, 87, 88, 89, 90]

def load_csv(path):
    if os.path.isfile(path):  # path 파일이 있다면
        with open(path, 'r', encoding='UTF-8') as csvf:
            data = pd.read_csv(csvf)
        return data
    else:
        print('path is wrong')

def convert_format_step2(labels_list, scores_list, boxes_list, data, index, h, w):
    pstring = data['PredictionString'][index]
    if type(pstring) is float and np.isnan(pstring):  # 해당 이미지에 대한 결과가 없다면 리턴
        return

    n_pstring = np.array(pstring.split(' '))
    n_pstring = np.delete(n_pstring, len(n_pstring) - 1)

    for idx in range(len(n_pstring) // 6):
        idx6 = idx * 6
        label = float(id_matching[int(n_pstring[idx6])])
        score = float(n_pstring[idx6 + 1])
        x1 = float(n_pstring[idx6 + 2]) / w
        y1 = float(n_pstring[idx6 + 3]) / h
        x2 = float(n_pstring[idx6 + 4]) / w
        y2 = float(n_pstring[idx6 + 5]) / h

        labels_list.append(label)
        scores_list.append(score)
        boxes_list.append([x1, y1, x2, y2])

def convert_format_step1(labels_lists, scores_lists, boxes_lists, weights, data, row_idx, model_idx, h, w, weights_size):
    labels_list = []
    scores_list = []
    boxes_list = []
    convert_format_step2(labels_list, scores_list, boxes_list, data, row_idx, h, w)
    if len(labels_list) != 0:
        weights.append(weights_size[model_idx])
        labels_lists.append(labels_list)
        scores_lists.append(scores_list)
        boxes_lists.append(boxes_list)

def do_ensemble(save_path, datas, weights_size):
    with open(save_path, 'wt', encoding='UTF-8') as coco:
        ann = []
        start0 = time.time()
        for row_idx in tqdm(range(len(datas[0]))):
            image_id = data0['image_id'][row_idx]
            w = data0['width'][row_idx]
            h = data0['height'][row_idx]

            labels_lists = []
            scores_lists = []
            boxes_lists = []
            weights = []

            for model_idx in range(len(datas)):
                convert_format_step1(labels_lists, scores_lists, boxes_lists, weights, datas[model_idx], row_idx,
                                     model_idx, h, w, weights_size)

            if len(labels_lists) == 0:
                continue
            else:
                # boxes, scores, labels = nms(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.5) # 0.439
                # boxes, scores, labels = soft_nms(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.5, sigma=0.1, thresh=0.0001) # 0.440
                # boxes, scores, labels = non_maximum_weighted(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.5, skip_box_thr=0.0001) # 0.447
                # boxes, scores, labels = weighted_boxes_fusion(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.5, skip_box_thr=0.0001) # 0.454
                # boxes, scores, labels = weighted_boxes_fusion(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.6, skip_box_thr=0.001) # 0.459
                boxes, scores, labels = weighted_boxes_fusion(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.7, skip_box_thr=0.001)  # 0.460
                # boxes, scores, labels = weighted_boxes_fusion(boxes_lists, scores_lists, labels_lists, weights=weights, iou_thr=0.8, skip_box_thr=0.001) # 0.459

                for c_idx in range(len(labels)):
                    ann += [{'image_id': int(image_id),
                             'category_id': int(labels[c_idx]),
                             'bbox': [boxes[c_idx][0] * w,
                                      boxes[c_idx][1] * h,
                                      (boxes[c_idx][2] - boxes[c_idx][0]) * w,
                                      (boxes[c_idx][3] - boxes[c_idx][1]) * h],
                             'score': float(scores[c_idx]), }]

        json.dump(ann, coco)
    print('{} images, duration time : {} [sec]'.format(len(data0), time.time() - start0))


if __name__ == '__main__':

    # 1. file load
    path0 = 'outputs/submission20.csv'  # 40.631
    path1 = 'outputs/submission21.csv'  # 42.036
    path2 = 'outputs/submission22.csv'  # 43.047
    data0 = load_csv(path0)
    data1 = load_csv(path1)
    data2 = load_csv(path2)
    datas = []
    datas.append(data0)
    datas.append(data1)
    datas.append(data2)

    # 2. format convert & ensemble
    weights_size = [1, 2, 3]
    save_path = 'outputs/ensemble.json'
    do_ensemble(save_path, datas, weights_size)

    # 3. evaluate COCO AP
    coco_gt = COCO('outputs/instances_val2017.json')
    image_ids = sorted(coco_gt.getImgIds())
    coco_dt = coco_gt.loadRes(save_path)
    coco_eval = COCOeval(coco_gt, coco_dt, 'bbox')
    coco_eval.params.imgIds = image_ids
    coco_eval.evaluate()
    coco_eval.accumulate()
    coco_eval.summarize()
<file_sep>/16. produce a data path list file/main.py
from generate_path_list_file import *
from integrate_file_list import *
from splite_train_val import *

if __name__ == '__main__':
    label = ['cat', 'dog']
    dir_path = ['dataset/1차', 'dataset/2차', 'dataset/3차']
    save_path = 'output'

    # 1. 지정 경로의 데이터셋 리스트 파일 만들기
    for i, v in enumerate(dir_path):
        generateFileList(save_path, v, label)

    # 2. 여러 리스트 파일을 통합
    integrateFilelist(save_path)

    # 3. train & val 나눠기 (통합 파일에서 랜덤으로 나눠기 or 각 폴더 별 랜덤으로 나눠기)
    #spliteDataset1(save_path, 8, 2)
    spliteDataset2(save_path, 8, 2)

    # 4. 눠어진 클래스 별 수 출력
    showClassCount(save_path, label)<file_sep>/04. simple websocket server node-express/webSocketServer.js
"use strict";
const funcs = require('./public/libs');  // 커스텀 라이브러리 불러오기
const WebSocket = require('ws');         // 웹소켓 라이브러리
const Hashtable = require('jshashtable');// 해시테이블 라이브러리
const wshashtable = new Hashtable();     // 해시테이블 생성
// global.wshashtable = wshashtable;     // 해시테이블 전역 변수화 시키기

module.exports = (server) => {
  // 웹소켓 서버 객체 생성
  const wss = new WebSocket.Server({ server });
  // 클라이언트 접속할 경우 그 클라이언트와 연결된 소켓객체(ws) 생성 
  wss.on('connection', (ws, req) => {
    // 웹 소켓 연결 시 클라이언트 정보 수집
    const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    const port = req.headers['x-forwarded-port'] || req.socket.remotePort;
    console.log('새로운 클라이언트 접속', ip);

    // 사전에 약속된 규칙으로 소켓서버 호출하여 변수 생성
    let conuri =  req.url; //wss://192.168.31.26:8000/wsid=1234&wstype=type1 <- 예시 소켓 호출 (로컬에서는 ws)
    let wsid = conuri.replace(/.+wsid=([^&]+).*/,"$1");
    let wstype= conuri.replace(/.+wstype=([^&]+).*/,"$1");

    // 소켓 연결 정보 해시 테이블에 저장
    wshashtable.put(wstype + wsid, ws);  

    if(wstype == "c++ws"){
      ws.send(JSON.stringify({ 
        optype:"server_msg",
        wsid: "server1",                 
        wstype:"server",
        msg : "Hi? I am Server!!!",
        count : 5,
        timestamp:funcs.timestamp()
      }))
    }

    // 클라이언트로부터 메시지 수신 시
    ws.on('message', (fmessage) => {     
      let msgjson = null;             
      try {               
        // 전달 받은 문자열 메시지(fmessage)를 자바스크립트 객체로 변환 
        msgjson = JSON.parse(fmessage);       
      } catch (error) {
        // 전달 받은 문자열이 JSON 형식이 아니라면 에러가 catch 부분으로 들어오게 됨.
        //console.log(`[JSON 타입이 아닌 메시지 수신] error : ${error}`);	
      }   
      
      // JSON 형식의 문자열로 수신된 메시지만 처리 되도록 함.
      if(msgjson){ 		
        // API 정의서 프로토콜을 정상적으로 지켰다면 모든 소켓 메시지들은 optype이라는 구분자로 각각의 처리를 구분 한다. 
        switch (msgjson.optype) {	
          // 클라이언트로 부터 받은 연결 확인 메시지 처리 부분 
          case 'init_websocket': 
            try {
              console.log(`[init_websocket] 메시지 : ${JSON.stringify(msgjson.msg)}`);
            }catch(error){
              console.log(`[init_websocket] error : ${error}`);
            }finally{
              break;
            }
          // 클라이언트로부터 받은 메시지를 처리하고 다시 응답 전달
          case 'client_msg': 
            try {
              console.log(`[client_msg]   메시지 : ${JSON.stringify(msgjson)}`);
              let count = msgjson.count - 1;
              if (count > 0){
                // 클라이언트로 응답 보내기
                ws.send(JSON.stringify({ 
                  optype:"server_msg",
                  wsid: "server1",                 
                  wstype:"server",
                  count : count,
                  timestamp:funcs.timestamp()
                }))
              }
            }catch(error){
              console.log(`[msg_test]      error : ${error}`);
            }finally{
              break;
            }
          default:
            // 약속된 optype이 아닌 경우 오류 메시지를 응답으로 전달
            console.log(`[잘못된 optype 수신] 전달 받은 optype과 매칭되는 api가 없습니다. : ${msgjson.optype}`);
            ws.send(`[잘못된 optype 수신] 전달 받은 optype과 매칭되는 api가 없습니다. : ${msgjson.optype}`);
            break;
        }
      }else{
        // 전달 받은 메시지가 JSON 타입이 아닐 경우 오류 메시지를 응답으로 전달
        console.log(`[JSON 타입이 아닌 메시지 수신]: (msg : ${fmessage}, ip : ${ip})`);
        ws.send(`[JSON 타입이 아닌 메시지 수신]: Successfully, a message has arrived. But this msg type is not JSON format. PLEASE SEND JSON TYPE FORMAT MESSAGE. (msg : ${fmessage}, ip : ${ip})`);
      }   
    });

    // 에러시
    ws.on('error', (error) => { 
      console.error(error);
    });

    // 연결 종료 시
    ws.on('close', () => {
      // 해시테이블에서 소켓 정보 제거 및 종료된 소켓 정보 출력
      wshashtable.remove(wstype + wsid);
      console.log(`[종료된 소켓 발생] ${funcs.timestamp()}`);   // 현재 시간 출력
      console.log(`[종료된 소켓 정보] 아이디 : ${wsid} / 접속 종류 : ${wstype} / 아이피 : ${ip} / 포트 : ${port}`);
      console.log(`[현재 접속 리스트] : ${wshashtable.keys()}`);
    });
  });
};<file_sep>/20. ensemble/README.md
# Ensemble
- Detectron2 (git commit id 5e38c1...)
- Faster RCNN R101-DC5
- Faster RCNN R101-FPN 
- Faster RCNN X101-FPN 
- COCO 2017 val Dataset
- Recommend to run in Colab


## Algorithms
- NMS : 내림차순 정렬 후, 가장 높은 스코어의 바운딩 박스를 기준으로 IOU 임곗값을 초과하는 바운딩 박스를 제거.


- soft NMS : NMS와 달리, 비교 과정에서 IOU 임곗값을 초과하는 박스를 그냥 제거하는 것이 아니라 스코어 값을 기존 보다 낮게 변경 처리함.


- NMW : 동일한 객체에 대해서 IOU 임곗값을 초과하는 바운딩 박스들의 그룹을 만들고 
각각의 IOU 값과 스코어 값으로 가중치를 만들어 그 그룹을 대표하는 값을 생성(라벨과 스코어는 그룹 중 스코어가 가장 높은 값 사용).


- WBF : 동일한 객체에 대해서 IOU 임곗값을 초과하는 바운딩 박스들의 그룹을 만들고 
모델에 대한 가중치 값이 적용된 스코어 값을 그 그룹에서 가중치로 사용하여 대표하는 값을 생성(라벨은 그룹 중 스코어가 가장 높은 값, 스코어는 평균값 사용).

## Performance Evaluation
- box AP (Average Precision at IoU=0.50:0.95, area=all)

<table border="0"  width="100%">
	<tbody align="center">
		<tr>
			<td>Faster RCNN backbone</td>
            <td>R101-DC5</td>
            <td>R101-FPN</td>
            <td>X101-FPN</td>
		</tr>
		<tr>
			<td>box AP</td>
			<td>40.631</td>
			<td>42.036</td>
			<td>43.047</td>
		</tr>
	</tbody>
</table>


<table border="0"  width="100%">
	<tbody align="center">
		<tr>
			<td>Ensemble Method</td>
            <td>NMS</td>
            <td>soft NMS</td>
            <td>NMW</td>
            <td><strong>WBF</strong></td>
		</tr>
		<tr>
			<td>box AP</td>
			<td>43.9</td>
			<td>44.0</td>
			<td>44.7</td>
			<td><strong>46.0</strong></td>
		</tr>
	</tbody>
</table>

## Description
- 다양한 앙상블 기법들을 실제로 계산을 통해 결과를 추출하였고 그 값들에 대해 비교 평가함.
- 모든 기법들의 결과값은 각 모델의 결과 보다 나은 성능을 보임.
- NMS와 soft-NMS의 경우 가장 높은 스코어를 갖는 바운딩 박스 하나만을 기준으로 겹치는 정도에 따라 나머지 바운딩 박스를 제거하는 방식으로 이루어지지만, 
NMW와 WBF의 경우 여러 바운딩 박스들의 정보를 종합하여 결과를 내기 때문에 더 우수한 것으로 보임.
- 특히, WBF의 경우 앙상블에서 쓰인 딥러닝 모델들의 가중치 값도 사용하기 때문에 NMW 보다 더 많은 정보를 기반으로 처리한다고 할 수 있음. 
그렇기 때문에 더 나은 성능을 나타낸 것으로 보임.


## Reference
- Detectron2 : <https://github.com/facebookresearch/detectron2>
- WBF : <https://arxiv.org/abs/1910.13302>
- soft NMS : <https://arxiv.org/abs/1704.04503>
- NMW : <https://openaccess.thecvf.com/content_ICCV_2017_workshops/papers/w14/Zhou_CAD_Scale_Invariant_ICCV_2017_paper.pdf>
- pycocotools : <https://github.com/cocodataset/cocoapi>
- ensemble-boxes : <https://github.com/ZFTurbo/Weighted-Boxes-Fusion><file_sep>/15. connection with DB in c++/DB/DB.cpp
﻿// 2021-8-17 by <NAME>
/***************************************************************************
	Simple DB 예제
****************************************************************************/
#include <iostream>
#include <mysql.h>

int main()
{
	MYSQL conn;
	mysql_init(&conn);
	MYSQL* connection = mysql_real_connect(&conn, "127.0.0.1", "root", "<PASSWORD>", "testdb", 3306, NULL, 0);
	
	if (!connection)
		std::cout << "mysql_real_connect() error" << std::endl;
	else
		std::cout << "mysql connection success" << std::endl;


	if (mysql_query(connection, "SELECT * FROM testtable where test_id = 1") != 0)
	{
		std::cout << "mysql_query() error" << std::endl;
	}

	MYSQL_RES* sql_results = mysql_store_result(connection);

	MYSQL_ROW sql_row;

	for (int rdx = 0; rdx < sql_results->row_count; rdx++)
	{
		sql_row = mysql_fetch_row(sql_results);
		for (int cdx = 0; cdx < sql_results->field_count; cdx++) 
		{
			std::cout << sql_row[cdx];
			if (cdx < sql_results->field_count - 1)std::cout << ", ";
		}
		std::cout << std::endl;
	}

	mysql_close(connection);
	return 0;
}<file_sep>/19. timm/tutorial_timm.py
import timm
import torch
from pprint import pprint

# timm 에서 제공 하는 모델 zoo 리스트
model_names = timm.list_models(pretrained=True)
pprint(model_names)

# feature extractor 로 사용 하기
model = timm.create_model('efficientnetv2_rw_s',features_only=True,  pretrained=True)
model.eval()
print(model)

print(f'Feature channels: {model.feature_info.channels()}')
o = model(torch.randn(2, 3, 224, 224))
for x in o:
  print(x.shape)


<file_sep>/14. connection with DB in python/db.py
import pymysql # pip install pymysql 설치

# python 예제 코드 실행 전 필요한 DB 작업
# 1. 설치되어있는 mysql에 접속
# > mysql -u root -p
# 2. root 계정 비밀번호 1234로 설정
# m> ALTER USER 'root'@'localhost' IDENTIFIED BY '1234';
# 3. testdb 데이터 베이스 생성.
# m> CREATE DATABASE testdb;
# m> USE testdb;
# 4. testtable 생성 sql
# m>create table testtable ( test_id int NOT NULL, test_value varchar(10) NULL, PRIMARY KEY(test_id));
# 5. 테스트용 데이터 삽입 sql
# m>insert into testtable (test_id, test_value) values(1, 'test data');

conn = pymysql.connect(
    user='root',        # db 계정 아이디
    password='<PASSWORD>',    # root 계정 비밀번호
    host='127.0.0.1',   # ip주소
    database='testdb',  # Database name
    port=3306,          # port는 최초 설치 시 입력한 값(기본값은 3306)
    charset='utf8'
)
#print(conn)
# db select, insert, update, delete 작업 객체
cursor = conn.cursor()
# 실행할 select 문 구성
sql = "SELECT * FROM testtable where test_id = 1"
# cursor 객체를 이용해서 수행한다.
cursor.execute(sql)
# select 된 결과 셋 얻어오기
resultList = cursor.fetchall()  # tuple 이 들어있는 list
#print(len(resultList))
print(resultList) # db에서 가져온 값
# DB 에 저장된 rows 출력해보기

for result in resultList:
    test_id = result[0]      # test_id
    test_value = result[1]   # test_value
    info = "test_id:{}, test_value :{}, ".format(test_id, test_value)
    print(info)


<file_sep>/13. show deep learning result on Web Browser/deep_learing_model/websocket_client.py
import asyncio
import websockets
import cv2
import base64
import numpy as np
import json
import torch, torchvision
import time
from torchvision import transforms
from datetime import datetime

inst_classes = [
    '__background__',
    'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
    'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
    'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
    'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
    'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]
transform = transforms.Compose([
    transforms.ToTensor(),
])
def timestamp() :
    return datetime.now().strftime('%Y-%m-%d %H:%M:%S')

async def connect(ip, port, wsid, wstype,model):

    # 웹 소켓에 접속
    async with websockets.connect("ws://{}:{}/wsid={}&wstype={}".format(ip, port,wsid, wstype)) as websocket:
        try:
            if websocket.open == True:
                init_websocket_msg = {
                    'optype': 'init_websocket',
                    'wsid': wsid,
                    'wstype': wstype,
                    'msg': 'Hello Server ? I am py',
                    'timestamp': timestamp()
                }
                jsonString = json.dumps(init_websocket_msg) # json 객체를 인코딩하여 string으로 만듬
                await websocket.send(jsonString)

            # python client 코드에서 웹소켓을 통해 영상을 웹으로 전달하는 로직

            capture = cv2.VideoCapture(0)  # 웹캠
            while 1 :

                ret, frame = capture.read()
                image_cv_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                image_tensor = transform(image_cv_rgb)
                image_tensor_4d = torch.unsqueeze(image_tensor, 0)  # 차원 추가 ex) [x,x,x] -> [1,x,x,x]

                boc = time.time()
                predictions = model(image_tensor_4d.to(device))
                eoc = time.time()

                fps = 1 / (eoc - boc)
                boxes = predictions[0]['boxes'].cpu().detach().numpy()
                scores = predictions[0]['scores'].cpu().detach().numpy()
                labels = predictions[0]['labels'].cpu().detach().numpy()

                for i, prob in enumerate(scores):
                    if prob > 0.99:
                        x0, y0, x1, y1 = boxes[i]
                        cv2.rectangle(frame, (int(x0), int(y0)), (int(x1), int(y1)), (0, 255, 0), 3)
                        cv2.putText(frame, inst_classes[labels[i]], (int(x0), int(y0)-5), cv2.FONT_HERSHEY_SIMPLEX, 1,
                                    (0, 255, 0), 2)

                    cv2.putText(frame, f"fps = {fps:.2f}", (15, frame.shape[0] - 15), cv2.FONT_HERSHEY_SIMPLEX, 1,
                                (0, 0, 0), 2)

                cv2.imshow("python", frame)
                if cv2.waitKey(1) == 27:
                    break  # esc to quit

                encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 100]
                result, encimg = cv2.imencode('.jpg', frame, encode_param)
                if False == result:
                    print('could not encode image!')

                # 이미지를 String 형태로 변환(인코딩)시키는 과정
                encoded = base64.b64encode(encimg).decode('utf-8')
                input_msg = {
                    'optype': 'output',
                    'wsid': wsid,
                    'wstype': wstype,
                    'frame': encoded,
                    'timestamp': timestamp()
                }
                jsonString = json.dumps(input_msg)  # json 객체를 인코딩하여 string으로 만듬
                await websocket.send(jsonString)

        except:
            print("error!!!")
            return 0

if __name__ == "__main__":

    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
    model.to(device)
    model.eval()

    ip = 'localhost'
    port = 8000
    wsid = 1
    wstype = 'pyc'
    asyncio.get_event_loop().run_until_complete(connect(ip, port, wsid, wstype,model))
    asyncio.get_event_loop().run_forever()
<file_sep>/12. image from browser to local with ws/websocket server nodejs/public/localVideo.js
'use strict';

// Video element where stream will be placed.
const localVideo = document.getElementById('local');

const Constraints = { video: true, audio: false  };
navigator.mediaDevices.getUserMedia(Constraints) // 1. 호출 후 브라우저는 사용자에게 카메라에 액세스 할 수 있는 권한을 요청
  .then(stream =>{                  // 2. stream을 가져옴
    localVideo.srcObject = stream;  // 3. srcObject속성을 통해 로컬 스트림을 (1) 화면에 출력
  })
  .catch(error =>{ // 2. 실패 할경우 에러 메시지 출력
    console.log('navigator.getUserMedia error: ', error);
  });<file_sep>/13. show deep learning result on Web Browser/deep_learing_model/pytorch_model.py
import torchvision, torch
from torchvision import transforms
import cv2
import time
from PIL import Image

inst_classes = [
    '__background__',
    'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
    'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
    'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
    'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
    'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]

if __name__ == '__main__':
    # train on the GPU or on the CPU, if a GPU is not available
    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')
    print(device)

    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
    model.to(device)
    model.eval()

    transform = transforms.Compose([
        transforms.ToTensor(),
    ])

    if 0: # one test image run
        file_path = "./dog.jpg"
        #image_pil = Image.open(file_path)
        #image = transform(image_pil)
        image_cv = cv2.imread("./dog.jpg")
        image_cv_rgb = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB)
        image_tensor = transform(image_cv_rgb)
        image_tensor_4d = torch.unsqueeze(image_tensor, 0) # 차원 추가 ex) [x,x,x] -> [1,x,x,x]

        predictions = model(image_tensor_4d.to(device)).cpu()

        boxes = predictions[0]['boxes'].detach().numpy()
        scores = predictions[0]['scores'].detach().numpy()
        labels = predictions[0]['labels'].detach().numpy()

        for i, prob in enumerate(scores):
            if prob > 0.9:
                x0, y0, x1, y1 = boxes[i]
                cv2.rectangle(image_cv,(int(x0),int(y0)),(int(x1),int(y1)),(0,255,0),3)
                cv2.imshow("test", image_cv)
                cv2.waitKey(0)
    else: # webcam run
        video = cv2.VideoCapture(0)
        while video.isOpened():
            success, frame = video.read()
            if success:

                image_cv_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                image_tensor = transform(image_cv_rgb)
                image_tensor_4d = torch.unsqueeze(image_tensor, 0)  # 차원 추가 ex) [x,x,x] -> [1,x,x,x]

                boc = time.time()
                predictions = model(image_tensor_4d.to(device))
                eoc = time.time()

                fps = 1 / (eoc-boc)
                boxes = predictions[0]['boxes'].cpu().detach().numpy()
                scores = predictions[0]['scores'].cpu().detach().numpy()
                labels = predictions[0]['labels'].cpu().detach().numpy()

                for i, prob in enumerate(scores):
                    if prob > 0.98:
                        x0, y0, x1, y1 = boxes[i]
                        cv2.rectangle(frame, (int(x0), int(y0)), (int(x1), int(y1)), (0, 255, 0), 3)
                        cv2.putText(frame, inst_classes[labels[i]], (int(x0), int(y0)), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0),2)

                    cv2.putText(frame, f"fps = {fps:.2f}", (15 , frame.shape[0] - 15), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255),2)

                cv2.imshow("test", frame)
                if cv2.waitKey(1) == 27:
                    break  # esc to quit

            else:
                print("video is wrong!")
                break
<file_sep>/11. simple python websocket server&client/server/server.py
# --------------------------------------------------------
# Simple Websocket Server
# Licensed under The MIT License
# Written by Derek
# 2021-06-27
# --------------------------------------------------------
import asyncio, websockets

'''
    간단한 파이썬 웹소켓 서버 구현
    클라이언트로 부터 메시지를 받으면 번갈아 가며 주고 받을수 있음.
'''

async def simpleServer(websocket, path):

    while True:
        client_msg = await websocket.recv()
        print('< [client] {}'.format(client_msg))

        resp = input('> [server] ')
        await websocket.send(resp)

port = 8000
start_server = websockets.serve(simpleServer, "localhost", port) # 웹소켓 객체 생성
print('Server on localhost:{}'.format(port))
asyncio.get_event_loop().run_until_complete(start_server)        # 비동기로 웹소켓 실행
asyncio.get_event_loop().run_forever()<file_sep>/12. image from browser to local with ws/websocket server nodejs/public/webSocketClient.js
'use strict';

const wsid = '2'
const wstype = 'webc'
const url = 'ws://localhost:8000'
const wsk = new WebSocket(`${url}/wsid=${wsid}&wstype=${wstype}`); // ws
let wsStatus = false;

wsk.onopen = function () {
    console.log('서버와 웹 소켓 연결됨');
    wsk.send(JSON.stringify({
      optype: "init_websocket",   // optype    : 동작 유형(init_websocket 클라이언트에서 연결 완료 후 서버로 확인 메시지 전달)
      wsid:   wsid,               // wsid      : 해당 소켓 아이디
      wstype: wstype,             // wstype    : 소켓 접속 유형
      msg : "Hello Server ? I am web client!!", // msg       : 메시지
      timestamp: timestamp()      // timestamp : 현재 시간
    }));
    wsStatus = true
};

wsk.onmessage = function (event) {
  let msgjson = JSON.parse(event.data);
  switch (msgjson.optype) {	
    case 'output': // python으로부터 이미지 수신
      let imaget = "data:image/jpg;base64," + msgjson.frame;  // img tag의 소스로 전달하기 위해 frame 정보에 헤더를 붙임
      document.getElementById("myimage").src = imaget;        // (4) 화면에 출력
      break;
    default:
      console.log('optype error : ' + msgjson.optype)
      break;
  }
}

wsk.onclose = function () {
    console.log("disconnected websocket")
    wsStatus = false;    
}

const canvas = document.getElementById('canvas');
const width = 350;
const height = 260;

function frame_capture() {
  const context = canvas.getContext('2d'); // canvas에 그려질 이미지를 2d로 값 설정
  context.drawImage(localVideo, 0, 0, width, height); // video tag의 영상을 canvas의 이미지로 갖고 온다. (2)출력
  if(wsStatus){ // 웹소켓이 연결 되었을때만 전송
    let frame = canvas.toDataURL('image/jpg', 1.0) // canvas에 그려진 이미지(base64 형태 소스)를 frame 변수에 담는다.
    wsk.send(JSON.stringify({ 
      optype: "input",   
      wsid:   wsid,              
      wstype: wstype,             
      frame : frame,     
      timestamp: timestamp()      
    }))
  }
}

setInterval(function() { frame_capture();}, 100); // 100ms마다 frame_capture() 함수 수행
<file_sep>/17. merge images in python/merge.py
import cv2
import numpy as np

output_image = cv2.imread('./result.png')
input_image = cv2.imread('./0030.jpg')

length = int(input_image.shape[0] / 1)

# crop piece from original image
small_image = input_image[:length:, :length]
big_image = output_image[:length * 4, :length * 4]

# Merge small image to big image
big_image[0:length, 0:length] = small_image

# draw outline
cv2.rectangle(big_image, (0, 0), (length, length), (0, 0, 255), 3)

# show
cv2.imshow('Merged_image', big_image)
cv2.waitKey(0)

# save
cv2.imwrite('./compare.png', big_image)
<file_sep>/16. produce a data path list file/generate_path_list_file.py
import os
import glob

'''
1. 지정 경로의 데이터셋 리스트 파일 만들기
*경로 리스트 파일 예시*
data path1, 클래스 인덱스
data path2, 클래스 인덱스
data path3, 클래스 인덱스

*로직
case1 -> 입력 폴더경로 아래 train or val 폴더가 존재 한다면, 그 안에 data들을 예시와 같은 형식으로 폴더명_train.txt 파일로 생성 (1차, 3차)
case2 -> 입력 폴더경로 아래 test 폴더가 존재 한다면, 그 안에 data들을 예시와 같은 형식으로 폴더명_test.txt 파일로 생성 (1차, 3차)
case3 -> 바로 클래스 폴더가 나오는 경우, 그 안에 data들을 아래 예시와 같은 형식으로 폴더명_train.txt 파일로 생성 (2차)

output:
output/list_file/1차_train.txt
output/list_file/2차_train.txt
output/list_file/3차_train.txt
output/list_file/1차_test.txt
output/list_file/3차_test.txt
'''

def generateFileList(save_path, dir_path, label):
    label_dict = {}
    for i, v in enumerate(label):
        label_dict[v] = i

    paths = [x for x in glob.iglob(dir_path + '/**') if os.path.isdir(x)]
    train_count = 0
    test_count = 0

    if not os.path.exists(save_path + '/list_file/'):  # 저장할 폴더가 없다면
        os.makedirs(save_path + '/list_file/')  # 폴더 생성
        print('make directory {} is done'.format(save_path + '/list_file/'))

    train_list_file = open(save_path + '/list_file/' + dir_path.split('/')[-1] + '_train.txt', 'w', encoding='utf-8')
    test_list_file = open(save_path + '/list_file/' + dir_path.split('/')[-1] + '_test.txt', 'w', encoding='utf-8')

    for elem in paths:
        sub_dir_name = elem.split('\\')[-1]

        # case1
        if sub_dir_name == 'train' or sub_dir_name == 'val':
            for jpg in [x for x in glob.iglob(elem + '/**', recursive=True)]:
                jpg = jpg.replace('\\', '/')
                if jpg.split('.')[-1] == 'jpg':
                    train_count += 1
                    train_list_file.writelines([f"{jpg}, {label_dict[jpg.split('/')[-2]]}\n"])

        # case2
        elif sub_dir_name == 'test':
            for jpg in [x for x in glob.iglob(elem + '/**', recursive=True)]:
                jpg = jpg.replace('\\', '/')
                if jpg.split('.')[-1] == 'jpg':
                    test_count += 1
                    test_list_file.writelines([f"{jpg}, {label_dict[jpg.split('/')[-2]]}\n"])

        # case3
        else:
            for jpg in [x for x in glob.iglob(elem + '/**', recursive=True)]:
                jpg = jpg.replace('\\', '/')
                if jpg.split('.')[-1] == 'jpg':
                    train_count += 1
                    train_list_file.writelines([f"{jpg}, {label_dict[jpg.split('/')[-2]]}\n"])

    print('train_count : {}, test_count : {}'.format(train_count, test_count))
    train_list_file.close()
    test_list_file.close()

    if train_count == 0:
        if os.path.isfile(train_list_file.name):
            os.remove(train_list_file.name)

    if test_count == 0:
        if os.path.isfile(test_list_file.name):
            os.remove(test_list_file.name)

if __name__ == '__main__':
    label = ['cat', 'dog']
    dir_path = ['dataset/1차', 'dataset/2차', 'dataset/3차']
    save_path = 'output'
    for i, v in enumerate(dir_path):
        generateFileList(save_path, v, label)<file_sep>/07. webRTC SFU server/webSocketServer.js
"use strict";
const funcs = require('./public/libs');  // 커스텀 라이브러리 불러오기
const WebSocket = require('ws');         // 웹소켓 라이브러리
const Hashtable = require('jshashtable');// 해시테이블 라이브러리
const wrtc = require('wrtc');            // webrtc 라이브러리 
const wshashtable = new Hashtable();     // 웹소켓 정보 저장 해시테이블 생성
const streamtable = new Hashtable();     // 스트림 저장 해시테이블 생성

module.exports = (server) => {
  // 웹소켓 서버 객체 생성
  const wss = new WebSocket.Server({ server });
  // 클라이언트 접속할 경우 그 클라이언트와 연결된 소켓객체(ws) 생성 
  wss.on('connection', (ws, req) => {
    // 웹 소켓 연결 시 클라이언트 정보 수집
    const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    const port = req.headers['x-forwarded-port'] || req.socket.remotePort;
    console.log('새로운 클라이언트 접속', ip);
    // 사전에 약속된 규칙으로 소켓서버 호출하여 변수 생성
    let conuri =  req.url; //wss://192.168.31.26:8000/wsid=1234&wstype=type1 <- 예시 소켓 호출 (로컬에서는 ws)
    let wsid = conuri.replace(/.+wsid=([^&]+).*/,"$1");
    let wstype= conuri.replace(/.+wstype=([^&]+).*/,"$1");

    // 소켓 연결 정보 해시 테이블에 저장
    wshashtable.put(wsid, ws);  
    wshashtable.keys().forEach(key =>{
      console.log("접속중인 소켓 아이디 :: " + key); 
      wshashtable.get(key).send(JSON.stringify({'optype': 'check_ws_num' ,'ws_count': wshashtable.keys().length}))
      console.log(key + " 로 업데이트된 웹소켓 접속수 전달")
    })

    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]} // stun 서버 주소
    var peerConnection = new wrtc.RTCPeerConnection(configuration); // RTCPeerConnection객체 생성
    let remoteStream = null;
    let localStream = null;

    if (wstype == 'sub' && streamtable.keys().length > 0){  
      console.log('[Downstream] send pub stream to sub client')
      localStream = streamtable.get('pub'); // 전달할 스트림이 있다면
    }else{
      console.log('[Downstream] no pub stream')
      localStream = new wrtc.MediaStream(); // 전달할 스트림이 없다면 빈 스트림 임시로 전달
    }
    
     // sub 클라이언트에게 전달할 스트림을 track에 추가
    localStream.getTracks().forEach(track => {
      console.log(localStream);
      peerConnection.addTrack(track, localStream);
    });  

    // pub에서 전달 받은 스트림을 해시테이블에 저장
    if (wstype == 'pub'){
      peerConnection.addEventListener('track', async (event) => {
        remoteStream = event.streams[0];
        streamtable.put('pub', remoteStream);
        console.log('[Upstream] find track and get pub stream !!')
        console.log(remoteStream)
      });
    }

    // 로컬의 ICE 후보를 수집 하기 위해 icecandidate를 이벤트로 등록
    peerConnection.addEventListener('icecandidate', event => {
      if (event.candidate) {
        console.log('[Listener] find new icecandidate!!')
        ws.send(JSON.stringify({optype : 'new-ice-candidate', icecandidate : event.candidate, 'wsid' : 'server'})); // 발견된 ICE를 클라이언트 피어로 전달
      }else{
        console.log('[Listener] All ICE candidates have been sent');
      }
    });

    // 연결 완료 상황을 알기 위해 connectionstatechange 이벤트 등
    peerConnection.addEventListener('connectionstatechange', event => {
      if (event) {
        console.log(`[Listener] 연결 상태 :: ${peerConnection.connectionState}`) // 연결 상태 체크
      }
    });

    async function treatOffer(peerConnection, offer){
      console.log("[수신측] 전달 받은 offer 내용을 수신측의 원격 정보로 등록.")
      await peerConnection.setRemoteDescription(new wrtc.RTCSessionDescription(offer));// 전달 받은 호출 측 메타 정보를 이용하여 세션 객체로 생성하고 원격 설정 내용에 등록
      const answer = await peerConnection.createAnswer(); // 수신 측 피어에 대한 정보를 담은 객체 생성
      await peerConnection.setLocalDescription(answer);  // 수신 측 피어 로컬 정보에 위 객체를 등록
      return answer
    }

    async function treatAnswer(peerConnection, answer){
      console.log("[호출측] 전달 받은 answer 내용을 호출측의 원격 정보로 등록")
      //console.log(answer);
      const remoteDesc = await new wrtc.RTCSessionDescription(answer); // 전달 받은 수신측 메타 정보로 세션 객체로 생성
      await peerConnection.setRemoteDescription(remoteDesc);  // 수신 측 세션 객체를 피어의 원격의 설정 내용에 등록
    }

    // 클라이언트로부터 메시지 수신 시
    ws.on('message', (fmessage) => {  
      let msgjson = JSON.parse(fmessage); 
      //console.log(msgjson)        
      switch (msgjson.optype) {	

        case 'send_ws_msg':
          console.log("send_ws_msg 요청 :: ")
          wshashtable.keys().forEach(key =>{
            if (key != msgjson.wsid ){
              wshashtable.get(key).send(fmessage)
            }
          })
          break;

        case 'initi_signal': 
          console.log("initi_signal 요청, ws_count ::" + wshashtable.keys().length);
          ws.send(JSON.stringify({'optype': 'initi_signal' ,'ws_count': wshashtable.keys().length}))
          break;

        case 'check_ws_num': 
          console.log("check_ws_num 요청, ws_count ::" + wshashtable.keys().length);
          ws.send(JSON.stringify({'optype': 'check_ws_num' ,'ws_count': wshashtable.keys().length}))
          break;

        case 'offer': 
          console.log("offer 요청 :: ")
          //console.log(msgjson.offer);
          wshashtable.keys().forEach(key =>{
            if (key == msgjson.wsid ){
              treatOffer(peerConnection, msgjson.offer)
              .then(answer =>{
                console.log("[수신측] 호출측으로 수신측의 peerConnection 정보가 담긴 answer 전달 ");
                ws.send(JSON.stringify({'optype': 'answer' ,'answer': answer, 'wsid' : wsid}));  // 호출 측에 응답으로 수신측 피어에 대한 메타 정보를 전달
              })
              console.log(key + " 로 offer 전달")
            }
          })
          break;

        case 'new-ice-candidate': 
          console.log("new-ice-candidate 요청 :: ")
          wshashtable.keys().forEach(key =>{
            if (key == msgjson.wsid ){
              peerConnection.addIceCandidate(msgjson.icecandidate); // 수신 받은 ICE를 등록
              console.log(key + " 로 new-ice-candidate 전달")
            }          
          })
          break;
        default:
          console.log('optype error : ' + msgjson.optype)
        }
    });

    // 에러시
    ws.on('error', (error) => { 
      console.error(error);
    });

    // 연결 종료 시
    ws.on('close', () => {
      // 해시테이블에서 소켓 정보 제거 및 종료된 소켓 정보 출력
      wshashtable.remove(wsid);
      console.log(`[종료된 소켓 발생] ${funcs.timestamp()}`);   // 현재 시간 출력
      console.log(`[종료된 소켓 정보] 아이디 : ${wsid} / 접속 종류 : ${wstype} / 아이피 : ${ip} / 포트 : ${port}`);
      console.log(`[현재 접속 리스트] : ${wshashtable.keys()}`);
      wshashtable.keys().forEach(key =>{    
        wshashtable.get(key).send(JSON.stringify({'optype': 'check_ws_num' ,'ws_count': wshashtable.keys().length}))
        console.log(key + " 로 업데이트된 웹소켓 접속수 전달")
      })
    });
  });
};<file_sep>/07. webRTC SFU server/public/webRTC_sub.js
"use strict"
var wsk = null;
var wsid = null;
// 스트림을 전달 받을 비디오 요소
var localVideo = document.querySelector('#localVideo');
var wscount = document.querySelector('p#wscount');
var ws_button = document.querySelector('#ws_button');

const Constraints = { video: true, audio: false  };
let localStream = null;
const remoteStream = new MediaStream(); //먼저 빈 인스턴스 생성
async function getUserMediaStream(Constraints){
  console.log('0. 클라인언트의 카메라에서 localstream을 불러오기');
  // 1. 호출 후 브라우저는 사용자에게 카메라에 액세스 할 수 있는 권한을 요청
  await navigator.mediaDevices.getUserMedia(Constraints)
    .then(stream =>{                  // 2. stream을 가져옴
      localVideo.srcObject = stream;  // 3. srcObject속성을 통해 로컬 스트림을 화면에 출력
      localStream = stream;           // 4. 로컬의 스트림을 localStream 변수에 전달
    })
    .catch(error =>{ // 2. 실패 할경우 에러 메시지 출력
      console.log('navigator.getUserMedia error: ', error);
    });
}
  // 시그널링을 위해 소켓 객체 생성
  async function try_ws_connect(){
    await getUserMediaStream(Constraints); // 로컬 스트림 처리 로직
    const videoTracks = await localStream.getVideoTracks();
    if(videoTracks.length > 0){
      console.log(`1. 클라이언트 장치 확인 : ${videoTracks[0].label}`) // 사용하는 카메라 장치 확인
    }
    var wsid_html = await document.getElementById("wsid").value;
    wsid = wsid_html;
    const wstype = 'sub'
    //const url = 'ws://192.168.31.77:8080' //https://0a810349c89b.ngrok.io   
    const url = 'wss://de93977e0955.ngrok.io'
    wsk = new WebSocket(`${url}/wsid=${wsid}&wstype=${wstype}`); // 웹소켓 연결 및 소켓 객체 생성
    console.log(`2. 웹소켓 연결 :: ${url}/wsid=${wsid}&wstype=${wstype}`)
    const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]} // stun 서버 주소
    const peerConnection = new RTCPeerConnection(configuration); // RTCPeerConnection객체 생성
 
    // 로컬 스트림을 track에 추가
    localStream.getTracks().forEach(track => {
      console.log('add local stream to track!!')
      peerConnection.addTrack(track, localStream);
      console.log(localStream);
    });      
    var remoteVideo = document.querySelector('#remoteVideo');
    // 원격에서 전달되는 스트림 수신하기 위해 새로 추가된 track이 있는지 확인하는 리스너
    peerConnection.addEventListener('track', async (event) => {
      if(remoteVideo.srcObject !== event.streams[0]){
        remoteVideo.srcObject = event.streams[0];   // 새로 발생된 track의 원격 스트림을 화면에 출력 
        console.log('[Listener] find track and get remote stream !!')
        //console.log(event);
        console.log(event.streams[0])
      }
    });
    // 로컬의 ICE 후보를 수집 하기 위해 icecandidate를 이벤트로 등록
    peerConnection.addEventListener('icecandidate', event => {
      if (event.candidate) {
        console.log('[Listener] find new icecandidate!!')
        wsk.send(JSON.stringify({optype : 'new-ice-candidate', icecandidate : event.candidate, 'wsid' : wsid})); // 발견된 ICE를 원격 피어로 전달
      }else{
        console.log('[Listener] All ICE candidates have been sent');
      }
    });
    // 연결 완료 상황을 알기 위해 connectionstatechange 이벤트 등
    peerConnection.addEventListener('connectionstatechange', event => {
      if (event) {
        console.log(`[Listener] 연결 상태 :: ${peerConnection.connectionState}`) // 연결 상태 체크
      }
    });
    async function getOffer(peerConnection){
      console.log("4. [호출측] 정보 준비 offer")
      const offer = await peerConnection.createOffer();   // 로컬에 대한 정보를 담은 객체 생성
      await peerConnection.setLocalDescription(offer);    // 이 객체를 로컬 설정에 등록
      //console.log(offer)
      return offer
    }
    async function treatOffer(peerConnection, offer){
      console.log("7. [수신측] 전달 받은 offer 내용을 수신측의 원격 정보로 등록.")
      await peerConnection.setRemoteDescription(new RTCSessionDescription(offer));// 전달 받은 호출 측 메타 정보를 이용하여 세션 객체로 생성하고 원격 설정 내용에 등록
      const answer = await peerConnection.createAnswer(); // 수신 측 피어에 대한 정보를 담은 객체 생성
      await peerConnection.setLocalDescription(answer);  // 수신 측 피어 로컬 정보에 위 객체를 등록
      return answer
    }
    async function treatAnswer(peerConnection, answer){
      console.log("10. [호출측] 전달 받은 answer 내용을 호출측의 원격 정보로 등록")
      //console.log(answer);
      const remoteDesc = await new RTCSessionDescription(answer); // 전달 받은 수신측 메타 정보로 세션 객체로 생성
      await peerConnection.setRemoteDescription(remoteDesc);  // 수신 측 세션 객체를 피어의 원격의 설정 내용에 등록
    }

    // 웹소켓 연결시
    wsk.onopen = function () {
      console.log('3. [웹소켓 연결 성공] 웹 소켓 서버와 연결 됨');
      wsk.send(JSON.stringify({'optype': 'initi_signal' ,'wsid' : wsid})); // 현재 접속해 있는 웹소켓 수 체크 
    };
    // 웹소켓 메시지 처리 
    wsk.onmessage = function (event) { 
      let msgjson = JSON.parse(event.data);
      switch (msgjson.optype) {	
        case 'initi_signal':
          getOffer(peerConnection)
          .then(offer =>{
            console.log("5. [호출측] peerConnection 정보가 담긴 offer를 수신측으로 전달");
            wsk.send(JSON.stringify({'optype': 'offer' ,'offer': offer, 'wsid' : wsid}));   // 웹소켓을 통해 호출 측 피어에 대한 메타 정보를 수신 측으로 전달
          }) 
          break;
        case 'check_ws_num':
          console.log("웹소켓 접속자 수 업데이트");
          wscount.innerHTML = "접속자 수 : " + msgjson.ws_count;
          break;
        case 'offer': 
          console.log("6. [수신측] offer 받음.")
          treatOffer(peerConnection, msgjson.offer)
          .then(answer =>{
            console.log("8. [수신측] 호출측으로 수신측의 peerConnection 정보가 담긴 answer 전달 ");
            wsk.send(JSON.stringify({'optype': 'answer' ,'answer': answer, 'wsid' : wsid}));  // 호출 측에 응답으로 수신측 피어에 대한 메타 정보를 전달
          })
          break;
        case 'answer':
          console.log("9. [호출측] answer 받음.")
          treatAnswer(peerConnection, msgjson.answer).then(()=>{
            console.log("11. [호출측] 수신받은 answer 처리 끝. :: ");
          })
          break;
        case 'new-ice-candidate':
          console.log('새로운 new-ice-candidate를 받음.')
          //console.log(msgjson.icecandidate)
          try {
            peerConnection.addIceCandidate(msgjson.icecandidate); // 수신 받은 ICE를 등록
            console.log('전달 받은 new-ice-candidate를 등록 완료')
          } catch (e) {
            console.error('Error adding received ice candidate', e);
          }
          break;
        default:
          console.log('optype error : ' + msgjson.optype)
          break;
      }
    };
    // 웹소켓 종료시
    wsk.onclose = function () {
      console.log('[웹소켓 연결 종료] 웹 소켓 서버와 연결이 종료 됨');
    };
  }
<file_sep>/09. simple web socket server c++/simpleServer/simpleServer.cpp
﻿#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/rapidjson.h>
#include <sstream>
#include <chrono>
#include <iostream>
#include <string>

using namespace std;
using namespace chrono;
using namespace rapidjson;

typedef websocketpp::server<websocketpp::config::asio> server;

using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;

string get_time_stamp()
{
	system_clock::time_point now = system_clock::now();
	system_clock::duration tp = now.time_since_epoch();

	tp -= duration_cast<seconds>(tp);

	time_t tt = system_clock::to_time_t(now);
	char time_str[1000];
	tm t = *localtime(&tt);
	sprintf(time_str, "%04u-%02u-%02u %02u:%02u:%02u.%03u", t.tm_year + 1900,
		t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
		static_cast<unsigned>(tp / milliseconds(1)));
	return time_str;
}

// pull out the type of messages sent by our config
typedef server::message_ptr message_ptr;

// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
	//std::cout << "on_message called with hdl: " << hdl.lock().get()
	//	<< " and message: " << msg->get_payload()
	//	<< std::endl;

	// check for a special command to instruct the server to stop listening so
	// it can be cleanly exited.
	if (msg->get_payload() == "stop-listening") {
		s->stop_listening();
		return;
	}
	int count = 5;
	std::string payload = msg->get_payload();
	cout << "msg=[" << payload << "]" << endl;

	Document d;
	d.Parse(payload.c_str());

	string optype = d["optype"].GetString();
	std::cout << optype << std::endl;
	if (optype == "client_msg") {
		count = d["count"].GetInt();
		count -= 1;
	}

	try {
		stringstream ss;
		ss << "{" << endl;
		ss << "\"optype\" : \"" << "server_msg" << "\"," << endl;
		ss << "\"wsid\" : \"" << "c++ server" << "\"," << endl;
		ss << "\"wstype\" : \"" << "server" << "\"," << endl;
		ss << "\"count\" : \"" << count << "\"," << endl;
		ss << "\"timestamp\" : \"" << get_time_stamp() << "\"" << endl;
		ss << "}" << endl;
		string output_buf = ss.str();
		s->send(hdl, output_buf, msg->get_opcode());
		cout << "opcode??=[" << msg->get_opcode() << "]" << endl;
	}
	catch (websocketpp::exception const & e) {
		std::cout << "Echo failed because: "
			<< "(" << e.what() << ")" << std::endl;
	}
}

int main() {
	// Create a server endpoint
	server echo_server;

	try {
		// Set logging settings
		echo_server.set_access_channels(websocketpp::log::alevel::all);
		echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);

		// Initialize Asio
		echo_server.init_asio();

		// Register our message handler
		echo_server.set_message_handler(bind(&on_message, &echo_server, ::_1, ::_2));

		// Listen on port 9002
		echo_server.listen(9002);

		// Start the server accept loop
		echo_server.start_accept();

		// Start the ASIO io_service run loop
		echo_server.run();
	}
	catch (websocketpp::exception const & e) {
		std::cout << e.what() << std::endl;
	}
	catch (...) {
		std::cout << "other exception" << std::endl;
	}
}
<file_sep>/README.md
# Useful toy project

If you know it, maybe you use it somewhere?
Anyway, code that seems to be useful code are. 


## index
1. Classify the detected object by class and save it as a file by python code
---
2. Making multiple images into video file by python code
---
3. Simple nodejs web server
---
4. Simple nodejs websocket server & client
---
5. Simple WebRTC Signal Server
---
6. WebRTC Signal Server
---
7. WebRTC SFU Server (pub -> server -> sub)
---
8. Simple C++ WebSocket Client
---
9. Simple C++ WebSocket Server
---
10. Base64 Encoding & Decoding with C++
---
11. Simple python WebSocket Server & Client
---
12. Sending and receiving webcam video by python web client
---
13. Output the python deep learning model results in a web browser
---
14. DB connection from python code
---
15. DB connection from C++ code
---
16. produce a data path list file with python
---
17. merge images with python
---
18. visualize coco format dataset
    - using [COCO dataset](https://cocodataset.org)
---
19. timm example
---
20. detection model ensemble
---<file_sep>/16. produce a data path list file/integrate_file_list.py
import os
import glob
import random

'''
2. 여러 리스트 파일을 통합
(2-1. 만약 test가 없다면 위 train 리스트 파일을 이용하여 train & test 리스트 파일 재생성)
output:
output/tot_train/tot_train.txt (1차_train.txt + 2차_train.txt + 3차_train.txt)
output/test/test.txt           (1차_test.txt + 3차_test.txt)
'''

def integrateFilelist(save_path, test_ratio=0.1):
    if not os.path.exists(save_path + '/tot_train/'):  # 저장할 폴더가 없다면
        os.makedirs(save_path + '/tot_train/')  # 폴더 생성
        print('make directory {} is done'.format(save_path + '/tot_train/'))

    if not os.path.exists(save_path + '/test/'):  # 저장할 폴더가 없다면
        os.makedirs(save_path + '/test/')  # 폴더 생성
        print('make directory {} is done'.format(save_path + '/test/'))

    tot_train_file = open(save_path + '/tot_train/tot_train.txt', 'w', encoding='utf-8')
    test_file = open(save_path + '/test/test.txt', 'w', encoding='utf-8')

    count_test_file = 0
    count_train_tot = 0
    train_path = []
    for txt in [x for x in glob.iglob(save_path + '/list_file/*.txt')]:
        txt = txt.replace('\\', '/')
        flag = txt.split('/')[-1].split('.')[0].split('_')[-1]

        if flag == 'test':
            count_test_file += 1
            f = open(txt, 'r', encoding='utf-8')
            lines = f.readlines()
            for line in lines:
                test_file.writelines(line)
            f.close()

        elif flag == 'train':
            f = open(txt, 'r', encoding='utf-8')
            lines = f.readlines()
            for line in lines:
                count_train_tot += 1
                tot_train_file.writelines(line)
                train_path.append(line)
            f.close()

    # 만약 train 데이터만 주어진다면 9:1 비율로 test 데이터 리스트 파일 생성
    if count_test_file == 0:
        print('There are no test list file. made test file {} ratio randomly'.format(test_ratio))
        test = int(count_train_tot * test_ratio + 0.5)
        test_loc = random.sample(range(1, count_train_tot), test)
        for n in range(test):
            test_file.writelines(train_path[test_loc[n]])
            train_path.remove(train_path[test_loc[n]])

        tot_train_file.close()
        if os.path.isfile(tot_train_file.name):
            os.remove(tot_train_file.name)
        tot_train_file = open(save_path + '/tot_train/tot_train.txt', 'w', encoding='utf-8')

        for i, v in enumerate(train_path):
            tot_train_file.writelines(v)

    tot_train_file.close()
    test_file.close()

if __name__ == '__main__':

    save_path = 'output'
    integrateFilelist(save_path)
<file_sep>/02. squence image to video/tt.py
# --------------------------------------------------------
# squence images to video file
# Licensed under The MIT License
# Written by Derek
# 2021-06-27
# --------------------------------------------------------
import cv2, os, time

'''
    연속 또는 무작위 다수 이미지 파일을 영상으로 만들기 
    데이터셋 출처 : https://motchallenge.net/data/MOT16/
'''

def imgs_to_video(output_dir_path, input_dir_path, video_name):
    boc = time.time()

    if not os.path.exists(output_dir_path):                         # 비디오를 저장할 폴더가 없다면
        os.makedirs(output_dir_path)                                # 폴더 생성
        print('make directory {} is done'.format(output_dir_path))

    video_name_ext = '{}.mp4'.format(video_name)                    # 비디오 파일 이름{input folder name}.mp4
    video_save_path = os.path.join(output_dir_path, video_name_ext) # 저장될 비디오 경로
    images_list = os.listdir(input_dir_path)                        # 이미지 파일 이름 리스트 불러오기

    first_image_path = os.path.join(input_dir_path, images_list[0]) # 첫번째 이미지 파일 경로
    first_image = cv2.imread(first_image_path)                      # 첫번째 이미지 로드
    height, width, layers = first_image.shape                       # 이미지 사이즈
    size = (width, height)                                          # 저장할 비디오 사이즈
    fps = 30                                                        # 저장할 비디오 fps
    out = cv2.VideoWriter(video_save_path, cv2.VideoWriter_fourcc(*'DIVX'), fps, size) # 비디오로 쓰기 위해 비디오 객체 생성

    for idx, image_name in enumerate(images_list):              # 이미지 저장 폴더에서 하나씩 꺼내오기
        img_path = os.path.join(input_dir_path, image_name)     # 각 이미지 파일 경로
        image = cv2.imread(img_path)                            # 이미지 로드
        out.write(image)                                        # 비디오 객체에 이미지 쓰기
        print('({}/{}) image to {} video'.format(idx, len(images_list), video_name_ext))

    out.release()                                               # 비디오 객체 메모리 해제

    print('====================================================================================')
    print('{}th images to {} video done!'.format(len(images_list), video_name_ext))
    print('Duration time is {} [sec]'.format(time.time() - boc))
    print('====================================================================================')

if __name__ == "__main__":

    input_dir_path = './MOT16-14/img1'   # 이미지들 저장 경로
    output_dir_path = './videos'         # 저장될 비디오 경로
    video_name = 'MOT16-14'              # 생성할 비디오 이름

    imgs_to_video(output_dir_path, input_dir_path, video_name)