Wip
This commit is contained in:
@ -9,10 +9,22 @@ export const minConfidence = 0.4;
|
||||
export const inputSize = 416;
|
||||
export const scoreThreshold = 0.5;
|
||||
|
||||
export const getFaceDetectorOptions = (net: faceapi.NeuralNetwork<any>) => {
|
||||
export const getFaceDetectorOptions = (
|
||||
net: faceapi.NeuralNetwork<any>,
|
||||
options?: {
|
||||
confidence?: number;
|
||||
inputSize?: number;
|
||||
scoreThreshold?: number;
|
||||
}
|
||||
) => {
|
||||
return net === faceapi.nets.ssdMobilenetv1
|
||||
? new faceapi.SsdMobilenetv1Options({ minConfidence })
|
||||
: new faceapi.TinyFaceDetectorOptions({ inputSize, scoreThreshold });
|
||||
? new faceapi.SsdMobilenetv1Options({
|
||||
minConfidence: options?.confidence ?? minConfidence,
|
||||
})
|
||||
: new faceapi.TinyFaceDetectorOptions({
|
||||
inputSize: options?.inputSize ?? inputSize,
|
||||
scoreThreshold: options?.scoreThreshold ?? scoreThreshold,
|
||||
});
|
||||
};
|
||||
|
||||
export const saveFile = async (
|
||||
|
@ -12,6 +12,7 @@ export interface IConfig extends PlatformConfig {
|
||||
debug?: boolean;
|
||||
writeOutput?: boolean;
|
||||
rate?: number;
|
||||
confidence?: number;
|
||||
}
|
||||
|
||||
export interface IRoom {
|
||||
|
@ -87,7 +87,8 @@ export class HomeLocationPlatform implements DynamicPlatformPlugin {
|
||||
if (this.config.trainOnStartup) {
|
||||
const trainer = new Trainer(
|
||||
this.config.refImageDirectory,
|
||||
this.config.trainedModelDirectory
|
||||
this.config.trainedModelDirectory,
|
||||
this.config.confidence
|
||||
);
|
||||
faceMatcher = await trainer.train(true);
|
||||
} else {
|
||||
|
@ -16,6 +16,7 @@ import { Event } from "../events";
|
||||
import { IConfig } from "../config";
|
||||
import { MonitorState } from "./monitorState";
|
||||
import { IStream } from "./stream";
|
||||
import sharp from "sharp";
|
||||
const { Canvas, Image, ImageData } = canvas;
|
||||
|
||||
const defaultWatchDog = 30000;
|
||||
@ -143,20 +144,36 @@ export class Monitor {
|
||||
this._config.watchdogTimeout ?? 30000
|
||||
);
|
||||
|
||||
const regularizedImgData = await sharp(args.data)
|
||||
.modulate({ brightness: 3 })
|
||||
.sharpen()
|
||||
.toBuffer();
|
||||
|
||||
//Detect faces in image
|
||||
const input = ((await canvas.loadImage(args.data)) as unknown) as ImageData;
|
||||
const input = ((await canvas.loadImage(
|
||||
regularizedImgData
|
||||
)) as unknown) as ImageData;
|
||||
const out = faceapi.createCanvasFromMedia(input);
|
||||
const resultsQuery = await faceapi
|
||||
.detectAllFaces(out, getFaceDetectorOptions(this._faceDetectionNet))
|
||||
.detectAllFaces(
|
||||
out,
|
||||
getFaceDetectorOptions(this._faceDetectionNet, {
|
||||
confidence: this._config.confidence,
|
||||
})
|
||||
)
|
||||
.withFaceLandmarks()
|
||||
.withFaceDescriptors();
|
||||
|
||||
//Write to output image
|
||||
if (this._config.writeOutput) {
|
||||
await saveFile(this._config.outputDirectory, room + ".jpg", args.data);
|
||||
await saveFile(
|
||||
this._config.outputDirectory,
|
||||
room + ".jpg",
|
||||
regularizedImgData
|
||||
);
|
||||
}
|
||||
for (const res of resultsQuery) {
|
||||
const bestMatch = this._matcher.matchDescriptor(res.descriptor);
|
||||
const bestMatch = this._matcher.findBestMatch(res.descriptor);
|
||||
const old = this._state[bestMatch.label];
|
||||
this._state[bestMatch.label] = room;
|
||||
this._stateChangedEvent.fire(this, {
|
||||
@ -165,9 +182,13 @@ export class Monitor {
|
||||
label: bestMatch.label,
|
||||
});
|
||||
|
||||
if (this._config.debug) {
|
||||
this._logger.info(`Face Detected: ${bestMatch.label} in room ${room}`);
|
||||
}
|
||||
this._logger.info(
|
||||
`Face Detected with ${
|
||||
res.detection.score * 100
|
||||
}% accuracy and a distance of ${bestMatch.distance}: ${
|
||||
bestMatch.label
|
||||
} in room ${room}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -78,6 +78,7 @@ export class Rtsp {
|
||||
const argStrings = [
|
||||
`-rtsp_transport tcp`,
|
||||
`-i ${this._connecteionString}`,
|
||||
`-qscale:v 1`,
|
||||
`-r ${this._options.rate ?? 10}`,
|
||||
`-vf mpdecimate,setpts=N/FRAME_RATE/TB`,
|
||||
this._options.image
|
||||
|
@ -12,7 +12,11 @@ const { Canvas, Image, ImageData } = canvas;
|
||||
faceapi.env.monkeyPatch({ Canvas, Image, ImageData });
|
||||
|
||||
export class Trainer {
|
||||
constructor(private _refImageDir: string, private _trainedModelDir: string) {}
|
||||
constructor(
|
||||
private _refImageDir: string,
|
||||
private _trainedModelDir: string,
|
||||
private _confidence?: number
|
||||
) {}
|
||||
|
||||
public async train(writeToDisk: boolean): Promise<faceapi.FaceMatcher> {
|
||||
const faceDetectionNet = faceapi.nets.ssdMobilenetv1;
|
||||
@ -24,18 +28,25 @@ export class Trainer {
|
||||
path.join(__dirname, "../weights")
|
||||
);
|
||||
|
||||
const options = getFaceDetectorOptions(faceDetectionNet);
|
||||
const options = getFaceDetectorOptions(faceDetectionNet, {
|
||||
confidence: this._confidence,
|
||||
});
|
||||
|
||||
const dirs = fs.readdirSync(this._refImageDir);
|
||||
|
||||
const refs = [];
|
||||
for (const dir of dirs) {
|
||||
const descriptor = new LabeledFaceDescriptors(dir, []);
|
||||
await this.getLabeledFaceDescriptorFromDir(
|
||||
path.join(this._refImageDir, dir),
|
||||
descriptor,
|
||||
options
|
||||
);
|
||||
try {
|
||||
await this.getLabeledFaceDescriptorFromDir(
|
||||
path.join(this._refImageDir, dir),
|
||||
descriptor,
|
||||
options
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
if (descriptor) {
|
||||
refs.push(descriptor);
|
||||
}
|
||||
@ -93,8 +104,11 @@ export class Trainer {
|
||||
|
||||
labeldFaceDescriptors.descriptors.push(descriptor.descriptor);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
"An error occurred loading image at path: " + path.join(dir, file)
|
||||
console.log(
|
||||
"An error occurred loading image at " +
|
||||
path.join(dir, file) +
|
||||
": " +
|
||||
err.message
|
||||
);
|
||||
}
|
||||
})
|
||||
|
Reference in New Issue
Block a user