临近春节,愈发不想干活了,心里只期待着早点放假…
公司最近布置了个任务,给每个人发了几千张图片,要求把每张图片的人脸标注出来。做深度学习的童鞋可能会有了解,标注这个过程就是用 LabelMe
这个软件一直做一些重复的机械劳动。懒如我,标了几张就觉得麻烦了,然后用 rust
写了个脚本实现标注完自动切换。脚本很简单,就是设置了触发后按照一定顺序自动帮你按下几个按键。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| use std::{thread::sleep, time::Duration};
use inputbot::{*, KeybdKey::*, MouseButton::*};
use inputbot::BlockInput::{Block, DontBlock};
fn main() {
const SLEEP_TIME: u64 = 50;
println!("按鼠标侧键触发自动切换");
X2Button.bind(|| {
LeftButton.press();
LeftButton.release();
sleep(Duration::from_millis(SLEEP_TIME));
EnterKey.press();
EnterKey.release();
sleep(Duration::from_millis(SLEEP_TIME));
EnterKey.press();
EnterKey.release();
sleep(Duration::from_millis(SLEEP_TIME));
DKey.press();
DKey.release();
sleep(Duration::from_millis(SLEEP_TIME));
EnterKey.press();
EnterKey.release();
sleep(Duration::from_millis(SLEEP_TIME));
EnterKey.press();
EnterKey.release();
sleep(Duration::from_millis(SLEEP_TIME));
EnterKey.press();
EnterKey.release();
});
handle_input_events();
}
|
用了这个脚本后,标注的时间的确大大减小了,我也就这么标了1000张,但是想到后面还有几千张,我吐了。为什么不做一个自动标注工具呢?说干就干,Let’s Roll~
分析了一下 LabelMe
的标注结果,其实就是标完点后生成了一个记录标的点的位置的 json
文件。因此,我们可以使用第三方人脸识别sdk来实现人脸检测,并把检测到的人脸坐标生成标注信息存储在 json
文件里,就大功告成了。
以下是整个过程核心方法的具体实现。通过这个工具,几千个标注瞬间干完了,省下的大把时间,又可以用来愉快的摸鱼了,奥里给!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| fun generateJsonFiles(path: String) {
val libDir = File("Win64")
val faceEngine = FaceEngine(libDir.absolutePath)
var errorCode = faceEngine.activeOnline(
"yourAppId",
"yourSdkKey"
)
if (errorCode != ErrorInfo.MOK.value && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.value) {
println("引擎激活失败")
return
} else {
println("引擎激活成功")
}
//引擎配置
val engineConfiguration = EngineConfiguration()
engineConfiguration.detectMode = DetectMode.ASF_DETECT_MODE_IMAGE
engineConfiguration.detectFaceOrientPriority = DetectOrient.ASF_OP_ALL_OUT
engineConfiguration.detectFaceMaxNum = 10
engineConfiguration.detectFaceScaleVal = 16
//功能配置
val functionConfiguration = FunctionConfiguration()
functionConfiguration.isSupportFaceDetect = true
functionConfiguration.isSupportFaceRecognition = true
engineConfiguration.functionConfiguration = functionConfiguration
//初始化引擎
errorCode = faceEngine.init(engineConfiguration)
if (errorCode != ErrorInfo.MOK.value) {
println("初始化引擎失败")
return
} else {
println("初始化引擎成功")
}
val fileTree = File(path).walk().maxDepth(1)
fileTree.filter { it.isFile && it.extension == "jpg" }
.forEach { imageFile ->
val imageInfo = ImageFactory.getRGBData(imageFile)
val faceInfoList = ArrayList<FaceInfo>()
faceEngine.detectFaces(
imageInfo.imageData,
imageInfo.width,
imageInfo.height,
imageInfo.imageFormat,
faceInfoList
)
if (faceInfoList.isNotEmpty()) {
val faces = mutableListOf<FloatArray>()
for (faceInfo in faceInfoList) {
//在此处微调人脸框大小
faces.add(floatArrayOf(faceInfo.rect.left.toFloat() + 10, faceInfo.rect.top.toFloat() - 10))
faces.add(floatArrayOf(faceInfo.rect.right.toFloat() - 10, faceInfo.rect.bottom.toFloat() + 5))
}
val imageData = encodeToBase64(imageFile.absolutePath)
val label = Label(
shapes = listOf(Shape(points = faces)),
imageData = imageData,
imagePath = imageFile.name
)
val json = jsonAdapter.toJson(label)
File(imageFile.parent, imageFile.nameWithoutExtension + ".json").writeText(json)
println("已处理${imageFile.name}")
} else {
println("未检测到人脸,跳过${imageFile.name}")
}
}
}
|
评论正在加载中...如果评论较长时间无法加载,你可以 搜索对应的 issue 或者 新建一个 issue 。