darknet format (다크넷 포맷) 은
클래스아이디, 바운딩 박스 중심 x좌표, 바운딩 박스 중심 y좌표, width, height 이다. (각각 resolution 값으로 나눠줘야함)
예시)
1 0.2 0.3 0.2 0.3
- 변환하려는 데이터
https://aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=realm&dataSetSn=176
AI-Hub
샘플 데이터 ? ※샘플데이터는 데이터의 이해를 돕기 위해 별도로 가공하여 제공하는 정보로써 원본 데이터와 차이가 있을 수 있으며, 데이터에 따라서 민감한 정보는 일부 마스킹(*) 처리가 되
aihub.or.kr
AI Hub의 데이터셋 라벨링 데이터는 보통 darknet format 으로 안 되어 있다. 변환을 해보자!
라벨링 파일 예시)
{
"image": {
"date": "20201126",
"path": "fire/Train/image",
"filename": "S3-N0806MF07391.jpg",
"copyrighter": "미디어그룹사람과숲(컨)",
"H_DPI": 96,
"location": "08",
"V_DPI": 96,
"bit": 24,
"resolution": [
1920,
1080
]
},
"annotations": [
{
"data ID": "S3",
"middle classification": "01",
"flags": "not occluded, not truncated",
"box": [
557,
446,
1052,
860
],
"class": "02"
}
]
}
해당 데이터셋의 구조 설명서를 읽어보면, box 좌표는 x1, y1, x2, y2 로 이뤄져 있다.
darknet format 으로 변경하기 위해서는
double xMiddle = (x2 + x1) / 2 / xRes;
double yMiddle = (y2 + y1) / 2 / yRes;
double width = (x2 - x1) / xRes;
double height = (y2 - y1) / yRes;
class, xMiddle , yMiddle , width , height 좌표로 변환해줘야 한다.
또, 변환하는데 필요한 프로퍼티는
- image- filename
- annotations - box
- annotations - class
가 있다.
데이터 학습시킬 때, 이미지와 어노테이션의 파일명이 같아야 하므로, 주의한다.
또한, 하나의 이미지에 여러개의 객체가 존재하거나, null 만 존재할 수 있다. 이를, 코드에 다 녹여야 한다.
라벨링 파일 예시) 데이터의 클래스 목록

01 클래스를 0 값으로 치환해주고 나머지도 순서대로 값을 매겨준다.
json 데이터를 클래스로 작성
Convert JSON to C# Classes Online - Json2CSharp Toolkit
json2csharp.com
에서 쉽게 코드를 받았다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnnotationToDarknetFormat
{// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Annotation
{
public string dataID { get; set; }
public string middleclassification { get; set; }
public string flags { get; set; }
public List<int> box { get; set; }
public List<List<int>> polygon { get; set; }
public string @class { get; set; }
}
public class Image
{
public string date { get; set; }
public string path { get; set; }
public string filename { get; set; }
public string copyrighter { get; set; }
public int H_DPI { get; set; }
public string location { get; set; }
public int V_DPI { get; set; }
public int bit { get; set; }
public List<int> resolution { get; set; }
}
public class Root
{
public Image image { get; set; }
public List<Annotation> annotations { get; set; }
}
}
- 변환코드)
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnnotationToDarknetFormat
{
class mainClass
{
static void Main(string[] args)
{
try
{
string rootPath = @"G:\fireProject_240105\화재 발생 예측 영상\Training\[라벨]유사씬\"; //json을 읽어올 경로
string[] files = Directory.GetFiles(rootPath, "*.json", SearchOption.AllDirectories);
string txtSavePath = rootPath + @"txt\";
DirectoryInfo dir = new DirectoryInfo(txtSavePath);
if (dir.Exists == false)
{
dir.Create();
}
foreach (var file in files)
{
if (File.Exists(file))
{
string txt = "";//텍스트 파일에 들어갈 내용, 저장 후 초기화 필요
string json = File.ReadAllText(file);
Root fileDatas = JsonConvert.DeserializeObject<Root>(json);
if (fileDatas != null) // null 가능성 고려
{
string fileName = fileDatas.image.filename;
string txtFileName = txtSavePath + fileName.Substring(0, fileName.IndexOf(".")) + ".txt";
if(File.Exists(txtFileName) == false)
{
double xRes = fileDatas.image.resolution[0];
double yRes = fileDatas.image.resolution[1];
if (fileName != null && xRes != 0 && yRes != 0 )
{
for (int i = 0; i < fileDatas.annotations.Count; i++) //각 이미지 당 여러 객체 존재가능
{
if(fileDatas.annotations[i] != null&& fileDatas.annotations[i].polygon ==null && fileDatas.annotations[i].box !=null)
{
int x1 = 0;
int y1 = 0;
int x2 = 0;
int y2 = 0;
x1 = fileDatas.annotations[i].box[0];
y1 = fileDatas.annotations[i].box[1];
x2 = fileDatas.annotations[i].box[2];
y2 = fileDatas.annotations[i].box[3];
string classID = fileDatas.annotations[i].@class;
if (classID != null && x1 != 0 && y1 != 0 && x2 != 0 && y2 != 0)
{
double xMiddle = (x2 + x1) / 2 / xRes;
double yMiddle = (y2 + y1) / 2 / yRes;
double width = (x2 - x1) / xRes;
double height = (y2 - y1) / yRes;
switch (classID)
{
case "01":
classID = "0";
break;
case "02":
classID = "1";
break;
case "03":
classID = "2";
break;
case "04":
classID = "3";
break;
case "05":
classID = "4";
break;
case "06":
classID = "5";
break;
case "07":
classID = "6";
break;
case "08":
classID = "7";
break;
case "09":
classID = "8";
break;
case "10":
classID = "9";
break;
case "11":
classID = "10";
break;
default:
break;
}
txt += classID + " " + xMiddle + " " + yMiddle + " " + width + " " + height + '\n';
}
}
}
File.WriteAllText(txtFileName, txt, Encoding.Default);
}
}
}
}
}
}
catch (Exception ex)
{
}
}
}
}
- json 데이터를 받아오고, DeserializeObject 해준다.
- 각 클래스에 맞는 필요한 값들을 변수로 저장해준다.
- 공식에 알맞게 값을 변환하고 txt 에 저장해준다.
- 실제 text 파일에 저장해준다.
- 파일이름은 이미지, json 과 동일하게 해준다.
'인공지능' 카테고리의 다른 글
[인공지능/리눅스] wsl 에 ubuntu 18.04 LTS 설치 / yolov5 설치 및 학습 (0) | 2023.09.20 |
---|