python의 __future__ 문 중에서 from __future__ import annotations는 함수나 클래스가 정의될 때 타입 힌트를 평가하지 않고 문자열 형태로 저장한다. 코드 작성과 유지보수가 훨씬 간단해지며 다음과 같은 상황에서 유용하다. 1. forward reference 간소화두 클래스가 서로 참조해야 할 때, 타임 이름을 문자열로 감싸야 'NameError'가 발생하지 않았는데 from __future__ import annotations를 사용하면 문자열로 감쌀 필요가 없다.class A: def __init__(self, b: 'B'): # 문자열로 감싸야 함 self.b = bclass B: def __init__(self, a: 'A'): ..
최근에 클래스 다이어그램을 그릴 일이 있었는데 draw.io로 그리려고 했는데 여간 귀찮은 게 아닌게 다른 방법은 없나 찾아보니 python 라이브러리인 pyreverse로 뚝딱 만들 수 있다는 걸 알게 됐다.draw.io를 사용해서 class diagram을 그리면 위와 같이 그릴 수 있다. 하지만 이번에는 pyreverse, pylint를 사용하여 정말 간단하게 그릴 수 있었다.1. pyreverse, pylint 설치pip install pyreversepip install pylintpylint를 설치하면 pyreverse도 같이 설치된다. 2. pyreverse 실행pyreverse -o png ./pyreverse -o [확장자명] [경로]경로에는 diagram을 그릴 폴더의 __init__..
영상에서 글자 인식을 위한 OCR 프로젝트를 하면서 전처리 과정에서 가장 잘 썼던 두 변환에 대해 정리하고자 한다. 1. Affine Transform : 영상의 이동, 전단, 확대, 회전을 조합할 때 직사각형이 평행사변형으로 변환이다. 쉽게 말하면 회전, 평행 이동, 스케일링, 반전까지 모두 포함한 변환이다. affine transform은 선의 평행성이 유지 되면서 변환된다. Affine 변환을 하기 위해 매칭되는 3개의 점(pts1, pts2)이 있어야만 변환 행렬을 구할 수 있다. 이 점 3개의 이동 정보를 통해 마지막 점의 위치를 유추할 수 있게 된다. cv2.getAffineTransform을 통해 변환 행렬을 구한 후 cv2.warpAffine으로 변환 행렬을 img에 적용 시켜주면 된다. ..
python에서 반복문을 사용하면서 for문이 얼마나 진행되었는지 확인할 수 있는 방법 중 하나가 tqdm을 사용하여 progress bar를 나타내는 것이다. tqdm을 사용하면 progress bar로 진행률을 나타내 주는 것만 아니라 남은 시간까지도 확인할 수 있다. from tqdm import tqdm import time for i in tqdm(range(10)): time.sleep(0.1) 기본 사용 방법은 위와 같다. tqdm으로 감싸는 값이 __len__()을 가지도록 하면 래와 같은 결과물이 나오게 된다. enumertae나 zip은 __len__()을 가지기 않기 때문에 조금 다르게 사용 해야 한다. a = [1,2,3,4] b = [5,6,7,8] enumerate(tqdm(a)..
협업을 하면서 내가 만든 코드를 다른 팀에서 모듈처럼 쓸 수 있도록 해야 하는 일이 생겼다. pip install package_name 형태로 사용할 수 있도록 패키지 화 해 달라고 했다. 1. repo 생성 가장 먼저 패키지로 사용할 repo를 새로 만들어야 한다. 기존 코드에서 구조가 달라져야 하기 때문에 새 repo를 만들어서 진행한다. 2. 패키지 구조 package_name package_name __init__.py function.py README.md requirements.txt setup.py 만들어 둔 repo와 연결 할 package 폴더의 구조를 위와 같이 만들어 준다. package 이름과 같은 폴더 안에 또 같은 폴더를 만든 후에 사용이 될 함수들을 만들어 놓아야 한다. 3...
파이썬에서 딕셔너리를 생성할 때 마다 a = {} a['key']='value' 이렇게만 해 왔는데 iterable하게 값을 넣어주려니(ex. value에 list를 넣는다는지 등등) for문을 써야하는 게 불편했다. 다른 방법이 있는지 알아보니 setdefault()라는 방법이 있었다. a = {} feature = np.array([1,2,3]) a.setdefault(0, []).append(feature) a >> {0:[array([1,2,3])]} 존재하지 않는 키에 대해서도 값을 넣을 수 있으며 feature2 = np.array([4,5,6]) a.setdefault(0, []).append(feature2) a >> {0:[array([1,2,3]), array([4,5,6])]} 키가 ..
ArUco marker는 검정색 테두리가 있는 이진 정사각형 이미지이다. 내부에 패턴은 마커 종류에 따라 다르다. camera calibration 및 stitching을 위해 ArUco Marker가 거의 필수적으로 사용이 된다. 특히 pose estimation은 비전 분야에서 정말 많이 사용된다. opencv를 사용하면 아래 marker 사전을 통해 쉽게 ArUco marker를 생성하고 detection하는 코드를 작성할 수 있다. # define names of each possible ArUco tag OpenCV supports ARUCO_DICT = { "DICT_4X4_50": cv2.aruco.DICT_4X4_50, "DICT_4X4_100": cv2.aruco.DICT_4X4_100,..
pytorch로 permute 함수를 사용하다가 transpose랑 비슷한 것 같은데 정확히 차이를 모르고 있구나 싶어서 찾아보고 기록하기 위해 해당 포스트를 작성하게 되었다. ◾ permute() 먼저, permute 함수는 모든 차원을 맞교환 할 수 있는 함수로 차원을 교환하면서 contiguous한 성질이 사라진다는 특징이 있다. permute() 괄호 안에 인덱스들을 바꾸고자 하는 위치대로 적어주면 된다. x = torch.rand(1, 2, 3) x1 = x.permute(2, 1, 0) >> output [3, 2, 1] 위 예시에서는 기존에 0,1,2번 인덱스를 가진 [1,2,3]을 2,1,0번 인덱스 순서로 바꿔 [3,2,1]로 바꿔주었기 때문에 output이 [3,2,1]이 되는 것이다...
pytorch를 사용하다 보면 모듈을 통해 나온 tensor를 사용할 일이 많은데, GPU에 올라가 있는 tensor를 이용하려면 numpy 또는 list로 변환하여야 한다. tensor를 numpy 또는 list로 변환하는 방법은 조금만 찾아보면여러 함수들이 나오긴 하지만 각 함수들을 사용하는 순서가 꽤 중요하기 때문에 자주 쓰는 방법을 기록한다. ◾ detach() pytorch는 tensor에서 이루어진 모든 연산을 기록(graph)해 놓는데 이 연산 기록에서 역전파가 이루어지게 된다. detach() 함수는 이 연산 기록에서 역전파를 중단하고 분리한 tensor를 반환한다. ◾ cpu() GPU 메모리에 올라가 있는 tensor를 CPU 메모리로 복사하는 함수이다. 이후에 numpy로 변환하기 위..
◾ squeeze 함수 squeeze 함수는 Tensor의 차원을 줄이는 함수로, 설정한 차원을 제거 해 준다. 따로 차원을 설정하지 않으면 1인 차원을 모두 제거한다. 1인 차원이 여러개 있어도 여러개 전부 다! 제거한다. import torch x = torch.rand(1,7,46,46) print(x.shape) # torch.Size([1, 7, 46, 46]) x = x.squeeze(dim=1) print(x.shape) # torch.Size([7, 46, 46]) 한가지 조심해야 할 것은 batch size가 1일 때 squeeze 함수를 사용하게 되면 batch 차원을 없애버려 validation 시 오류가 발생하게 된다. 이걸 간과하고 있어서 학습할 때 validation에서 계속 오..