初次提交

This commit is contained in:
2025-03-06 14:38:32 +08:00
commit b0e71d0ebb
46 changed files with 1926 additions and 0 deletions

View File

@ -0,0 +1,103 @@
import { cv } from "../../cv"
import { ImageSource, Model } from "../common/model"
interface IFaceBoxConstructorOption {
x1: number
y1: number
x2: number
y2: number
score: number
imw: number
imh: number
}
export class FaceBox {
#option: IFaceBoxConstructorOption;
constructor(option: IFaceBoxConstructorOption) { this.#option = option; }
public get x1() { return this.#option.x1; }
public get y1() { return this.#option.y1; }
public get x2() { return this.#option.x2; }
public get y2() { return this.#option.y2; }
public get centerX() { return this.x1 + this.width / 2; }
public get centerY() { return this.y1 + this.height / 2; }
public get score() { return this.#option.score; }
public get left() { return this.x1; }
public get top() { return this.y1; }
public get width() { return this.x2 - this.x1; }
public get height() { return this.y2 - this.y1; }
/** 转换成整数 */
public toInt() {
return new FaceBox({
...this.#option,
x1: parseInt(this.#option.x1 as any), y1: parseInt(this.#option.y1 as any),
x2: parseInt(this.#option.x2 as any), y2: parseInt(this.#option.y2 as any),
});
}
/** 转换成正方形 */
public toSquare() {
const { imw, imh } = this.#option;
let size = Math.max(this.width, this.height) / 2;
const cx = this.centerX, cy = this.centerY;
console.log(this)
if (cx - size < 0) size = cx;
if (cx + size > imw) size = imw - cx;
if (cy - size < 0) size = cy;
if (cy + size > imh) size = imh - cy;
return new FaceBox({
...this.#option,
x1: this.centerX - size, y1: this.centerY - size,
x2: this.centerX + size, y2: this.centerY + size,
});
}
}
export interface FaceDetectOption {
/** 阈值默认0.5 */
threshold?: number
/** MNS阈值默认0.3 */
mnsThreshold?: number
}
export abstract class FaceDetector extends Model {
protected abstract doPredict(image: cv.Mat, option?: FaceDetectOption): Promise<FaceBox[]>;
public async predict(image: ImageSource, option?: FaceDetectOption) { return Model.resolveImage(image, im => this.doPredict(im, option)); }
}
export function nms(input: FaceBox[], threshold: number) {
if (!input.length) return [];
input = input.sort((a, b) => b.score - a.score);
const merged = input.map(() => 0);
const output: FaceBox[] = [];
for (let i = 0; i < input.length; i++) {
if (merged[i]) continue;
output.push(input[i]);
for (let j = i + 1; j < input.length; j++) {
if (merged[j]) continue;
const inner_x0 = input[i].x1 > input[j].x1 ? input[i].x1 : input[j].x1;
const inner_y0 = input[i].y1 > input[j].y1 ? input[i].y1 : input[j].y1;
const inner_x1 = input[i].x2 < input[j].x2 ? input[i].x2 : input[j].x2;
const inner_y1 = input[i].y2 < input[j].y2 ? input[i].y2 : input[j].y2;
const inner_h = inner_y1 - inner_y0 + 1;
const inner_w = inner_x1 - inner_x0 + 1;
if (inner_h <= 0 || inner_w <= 0) continue;
const inner_area = inner_h * inner_w;
const h1 = input[j].y2 - input[j].y1 + 1;
const w1 = input[j].x2 - input[j].x1 + 1;
const area1 = h1 * w1;
const score = inner_area / area1;
if (score > threshold) merged[j] = 1;
}
}
return output;
}