라벨링 데이터 회전하여 증분 90도 180도 (python labeling data rotate) :: 개발/일상_Mr.lee

라벨링 데이터 회전하여 증분 90도 180도 (python labeling data rotate)

Posted by Mr.mandu.
2020. 6. 26. 07:00 개발/python, 딥러닝

안녕하세요.

오늘은 딥러닝 라벨링 데이터를 증분시키는 포스팅을 해보겠습니다.

사실 별 내용은 없지만 엄청 고생했네요.

아마 물체 탐지, YOLO 사용을 하시는분들은 

데이터 증분을 위해 필수적으로 필요하다고 생각합니다.



먼저 이와 같은 이미지가 있습니다.

사이즈는 847 x 505 입니다.

이 데이터의 글자인 영역을 라벨링 해보겠습니다.

(라벨링 이라고도하고 레이블링 이라고도 합니다.)


이렇게 문자영역에 대해서 라벨링을 하였습니다.

이렇게 라벨링을 하면 xml 파일이 생성 됩니다.


<annotation>
	<folder>japan</folder>
	<filename>0.JPG</filename>
	<path>E:\source\tensor2_0_source\test\japan\0.JPG</path>
	<source>
		<database>Unknown</database>
	</source>
	<size>
		<width>847</width>
		<height>505</height>
		<depth>3</depth>
	</size>
	<segmented>0</segmented>
	<object>
		<name>가</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>655</xmin>
			<ymin>142</ymin>
			<xmax>690</xmax>
			<ymax>178</ymax>
		</bndbox>
	</object>
	<object>
		<name>나</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>502</xmin>
			<ymin>325</ymin>
			<xmax>536</xmax>
			<ymax>360</ymax>
		</bndbox>
	</object>
</annotation>


별 내용은 없습니다.

물체 탐지 혹은 YOLO를 사용하시는 분들은 라벨링 프로그램의 사용법을 다 아실 것이며

xml 파일도 위와같이 떨어지는 것을 아실거라 생각합니다.


인공지능에 대한 키 포인트는 학습데이터 입니다.

학습데이터 생성을 위해 라벨링을 하여 데이터를 만들었습니다.

하지만 사람이 일일이 하기에는 어려움이 있습니다.

그리고 문자가 회전되있을지 뒤짚어져 있는 데이터가 오면 탐지하지 못하는 경우가 발생합니다.

아래와 같이 말이죠.



라벨링을 통해 학습데이터를 만들었고 '가', '나' 를 학습시켰습니다.

하지만 문자가 뒤짚어져 있으면 탐지하지 못한다는 거죠.

그리고 데이터 수가 부족해서 학습이 덜 됬을수도 있고요.


그래서 우리는 데이터의 증분이 필요합니다.


이미지 회전을 통한 데이터 증분

일반적으로 파이썬을 통하여 cv2나 pillow를 통하여 이미지를 회전 시킬수 있습니다.

하지만 학습데이터의 정보가 들어 있는 xml 파일은 변하지 않죠.


이를 찾기위해 이틀은 검색을 하였습니다.

첫번째로, 처음에 접근 방법은 움직이는 각도만큼의 수치를 계산하여 좌표를 이동시키려 했습니다.

검색결과 각도에 대한 좌표이동은 쉽지 않고 정확도도 떨어진다고 합니다.

sin, cos 수식 대입해서 결과를 확인하였습니다.


두번째로, imgaug 라이브러리를 설치하여 데이터를 증분 시키라는 내용도 있었습니다.

하지만 저는 읽고 포기하였습니다. 저와 맞지 않다고 생각했기때문입니다.


마지막으로, 이미지 이동을 예상하여 직접 수치 계산을 하였습니다.

이게 제일 간단한 방법인데도 검색해도 나오질 않았습니다.


먼저 이미지를 회전 시킵니다.

from PIL import Image, ImageFilter

# 이미지 회전하기
img = Image.open(file)
img_new = img.transpose(method=Image.ROTATE_90)
img_new.save(file, quality=100)     # 회전한 파일 저장하기.



Imge.open(file) 부분에는 본인의 파일 경로와 파일을 적어주어야 합니다.

그리고 기존 좌표를 구합니다.

       doc = ET.parse(file_xml)
        root = doc.getroot()

        for object in root.iter("object"):

            # 기존 좌표 구하기
            xmin = object.find("bndbox").findtext("xmin")
            ymin = object.find("bndbox").findtext("ymin")
            xmax = object.find("bndbox").findtext("xmax")
            ymax = object.find("bndbox").findtext("ymax")

위의 소스는 xml 파일을 파싱해서 데이터를 가져온 것입니다.

이전 포스팅을 참고해주세요.

[개발/python, 딥러닝] - 파이썬 xml 태그값 가져오기 및 파싱


이제 이미지가 90도 회전과, 180도 회전을 통해서 

기존 좌표가 어떻게 변하는지 원리를 파악하셔야 합니다.

90도로 회전시켰을 시,

기존 이미지 사이즈 : 847 x 505

회전 이미지 사이즈 : 505 x 847

즉, 가로와 세로가 바뀐다는 점 입니다.


이렇게 회전하는 이미지에 대한 좌표 변환 입니다.

# 이미지 크기 구하기 w, h = img.size # 좌표 재생성 object.find("bndbox").find("xmin").text = ymin object.find("bndbox").find("ymin").text = str(cal_90_point(int(xmin), w)) object.find("bndbox").find("xmax").text = ymax object.find("bndbox").find("ymax").text = str(cal_90_point(int(xmax), w)) #xml 파일에 다시 쓰기 doc.write(file_xml)




변형된 xmin과 xmax 는 기존의 ymin과 ymax 를 적어주시면 되고

변형된 ymin과 ymax 는 넓이(width)에서 각 xmin과 xmax를 빼주시면 됩니다.

ymin과 ymax는 좌표가 그대로 변환되는게 아니고 넓이를 기준으로 하기 때문입니다.


#90 도 변형 소스
def cal_90_point(p1, width):
 new_point = width - p1
 return new_point

이미지 회전 및 좌표 회전 결과입니다.


추가로 180도 회전에 대한 좌표 구하는 함수를 적겠습니다.

180도는 대칭 이동하기때문에 2배의 거리에서 기존 거리를 빼주시면 됩니다.

#180도 회전
def cal_180_point(p1, p2):
 new_p = p2 * 2 - p1
return new_p

혹시나 이해가 안되는 점이 있다면

댓글로 설명해드리겠습니다.


감사합니다.